Browse Source

build pass

Robert 2 năm trước cách đây
mục cha
commit
d310848fbd
100 tập tin đã thay đổi với 14362 bổ sung946 xóa
  1. 25 0
      .dockerignore
  2. 29 0
      Dockerfile
  3. 24 24
      EVCB_OCPP.Server.sln
  4. 0 0
      EVCB_OCPP.WSServer.backup/App.config
  5. BIN
      EVCB_OCPP.WSServer.backup/DLL/EVCB_OCPP.Domain.dll
  6. BIN
      EVCB_OCPP.WSServer.backup/DLL/EVCB_OCPP.Packet.dll
  7. BIN
      EVCB_OCPP.WSServer.backup/DLL/EVCB_OCPP20.Packet.dll
  8. 0 0
      EVCB_OCPP.WSServer.backup/DLL/SuperSocket.Common.dll
  9. 0 0
      EVCB_OCPP.WSServer.backup/DLL/SuperSocket.SocketBase.dll
  10. 0 0
      EVCB_OCPP.WSServer.backup/DLL/SuperSocket.SocketEngine.dll
  11. 0 0
      EVCB_OCPP.WSServer.backup/DLL/SuperWebSocket.dll
  12. 65 0
      EVCB_OCPP.WSServer.backup/Dto/ChargingPrice.cs
  13. 20 0
      EVCB_OCPP.WSServer.backup/Dto/ConnectorErrorStauts.cs
  14. 25 0
      EVCB_OCPP.WSServer.backup/Dto/ErrorDetails.cs
  15. 21 0
      EVCB_OCPP.WSServer.backup/Dto/ID_GetTxUserInfo.cs
  16. 38 0
      EVCB_OCPP.WSServer.backup/Dto/IdTokenInfo.cs
  17. 37 0
      EVCB_OCPP.WSServer.backup/Dto/StationFee.cs
  18. 18 0
      EVCB_OCPP.WSServer.backup/Dto/TCCStationInfoDto.cs
  19. 16 0
      EVCB_OCPP.WSServer.backup/Dto/TCCWeatherDto.cs
  20. 17 0
      EVCB_OCPP.WSServer.backup/Dto/TransactionEnergy.cs
  21. 247 0
      EVCB_OCPP.WSServer.backup/EVCB_OCPP.WSServer.csproj
  22. 6 0
      EVCB_OCPP.WSServer.backup/GitVersion.yml
  23. 143 0
      EVCB_OCPP.WSServer.backup/GlobalConfig.cs
  24. 24 0
      EVCB_OCPP.WSServer.backup/Helper/Convertor.cs
  25. 155 0
      EVCB_OCPP.WSServer.backup/Message/BasicMessageHandler.cs
  26. 1656 0
      EVCB_OCPP.WSServer.backup/Message/CoreProfileHandler.cs
  27. 228 0
      EVCB_OCPP.WSServer.backup/Message/FirmwareManagementProfileHandler.cs
  28. 109 0
      EVCB_OCPP.WSServer.backup/Message/LocalAuthListManagementProfileHandler.cs
  29. 54 0
      EVCB_OCPP.WSServer.backup/Message/MessageResult.cs
  30. 50 0
      EVCB_OCPP.WSServer.backup/Message/NeedConfirmMessage.cs
  31. 347 0
      EVCB_OCPP.WSServer.backup/Message/OCPP16MessageHandler.cs
  32. 297 0
      EVCB_OCPP.WSServer.backup/Message/OCPP20MessageHandler.cs
  33. 86 0
      EVCB_OCPP.WSServer.backup/Message/RemoteTriggerHandler.cs
  34. 125 0
      EVCB_OCPP.WSServer.backup/Message/ReservationProfileHandler.cs
  35. 73 0
      EVCB_OCPP.WSServer.backup/Message/SecurityProfileHandler.cs
  36. 208 0
      EVCB_OCPP.WSServer.backup/Message/SmartChargingProfileHandler.cs
  37. 0 0
      EVCB_OCPP.WSServer.backup/NLog.config
  38. 0 0
      EVCB_OCPP.WSServer.backup/NLog.xsd
  39. 46 0
      EVCB_OCPP.WSServer.backup/Program.cs
  40. 38 0
      EVCB_OCPP.WSServer.backup/Properties/AssemblyInfo.cs
  41. 2171 0
      EVCB_OCPP.WSServer.backup/ProtalServer.cs
  42. 36 0
      EVCB_OCPP.WSServer.backup/Service/BusinessServiceFactory.cs
  43. 365 0
      EVCB_OCPP.WSServer.backup/Service/HttpClientService.cs
  44. 393 0
      EVCB_OCPP.WSServer.backup/Service/LoadingBalanceService.cs
  45. 92 0
      EVCB_OCPP.WSServer.backup/Service/LocalBusinessService.cs
  46. 240 0
      EVCB_OCPP.WSServer.backup/Service/OuterBusinessService.cs
  47. 214 0
      EVCB_OCPP.WSServer.backup/Service/OuterHttpClient.cs
  48. 18 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Command/ProcessCallCmd.cs
  49. 18 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Command/ProcessCallErrorCmd.cs
  50. 18 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Command/ProcessCallResultCmd.cs
  51. 128 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/ClientData.cs
  52. 441 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPLog.cs
  53. 31 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPLogFactory.cs
  54. 0 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPSubCommandParser.cs
  55. 322 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPSubProtocol.cs
  56. 215 0
      EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPWSServer.cs
  57. 0 0
      EVCB_OCPP.WSServer.backup/packages.config
  58. 1 0
      EVCB_OCPP.WSServer.backup/upgrade.backup
  59. BIN
      EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Domain.dll
  60. BIN
      EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Packet.dll
  61. 29 0
      EVCB_OCPP.WSServer/Dockerfile
  62. 30 195
      EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj
  63. 7 27
      EVCB_OCPP.WSServer/GlobalConfig.cs
  64. 9 8
      EVCB_OCPP.WSServer/Message/BasicMessageHandler.cs
  65. 85 68
      EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs
  66. 8 7
      EVCB_OCPP.WSServer/Message/FirmwareManagementProfileHandler.cs
  67. 3 7
      EVCB_OCPP.WSServer/Message/LocalAuthListManagementProfileHandler.cs
  68. 5 4
      EVCB_OCPP.WSServer/Message/OCPP16MessageHandler.cs
  69. 5 4
      EVCB_OCPP.WSServer/Message/OCPP20MessageHandler.cs
  70. 2 2
      EVCB_OCPP.WSServer/Message/RemoteTriggerHandler.cs
  71. 4 4
      EVCB_OCPP.WSServer/Message/ReservationProfileHandler.cs
  72. 4 3
      EVCB_OCPP.WSServer/Message/SecurityProfileHandler.cs
  73. 6 6
      EVCB_OCPP.WSServer/Message/SmartChargingProfileHandler.cs
  74. 52 7
      EVCB_OCPP.WSServer/Program.cs
  75. 4 4
      EVCB_OCPP.WSServer/Properties/AssemblyInfo.cs
  76. 10 0
      EVCB_OCPP.WSServer/Properties/launchSettings.json
  77. 247 57
      EVCB_OCPP.WSServer/ProtalServer.cs
  78. 25 4
      EVCB_OCPP.WSServer/Service/BusinessServiceFactory.cs
  79. 7 5
      EVCB_OCPP.WSServer/Service/LoadingBalanceService.cs
  80. 7 6
      EVCB_OCPP.WSServer/Service/LocalBusinessService.cs
  81. 20 14
      EVCB_OCPP.WSServer/Service/OuterBusinessService.cs
  82. 1 0
      EVCB_OCPP.WSServer/SuperSocket.Command/ProcessCallCmd.cs
  83. 1 0
      EVCB_OCPP.WSServer/SuperSocket.Command/ProcessCallErrorCmd.cs
  84. 1 0
      EVCB_OCPP.WSServer/SuperSocket.Command/ProcessCallResultCmd.cs
  85. 4 2
      EVCB_OCPP.WSServer/SuperSocket.Protocol/ClientData.cs
  86. 1 434
      EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPLog.cs
  87. 1 27
      EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPLogFactory.cs
  88. 35 0
      EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPSubCommandConverter.cs
  89. 8 8
      EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPSubProtocol.cs
  90. 39 19
      EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPWSServer.cs
  91. 1449 0
      EVCB_OCPP.WSServer/UpgradeReport.sarif
  92. 93 0
      EVCB_OCPP.WSServer/appsettings.json
  93. 373 0
      SocketBase.backup/AppServer.cs
  94. 159 0
      SocketBase.backup/AppServerBase.ConfigHotUpdate.cs
  95. 51 0
      SocketBase.backup/AppServerBase.Net45.cs
  96. 1723 0
      SocketBase.backup/AppServerBase.cs
  97. 689 0
      SocketBase.backup/AppSession.cs
  98. 143 0
      SocketBase.backup/Async.cs
  99. 53 0
      SocketBase.backup/Command/CommandBase.cs
  100. 39 0
      SocketBase.backup/Command/CommandInfo.cs

+ 25 - 0
.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

+ 29 - 0
Dockerfile

@@ -0,0 +1,29 @@
+#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/aspnet:7.0 AS base
+RUN sed -i 's/TLSv1.2/TLSv1/g' /etc/ssl/openssl.cnf
+RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
+EXPOSE 80
+EXPOSE 443
+EXPOSE 54088
+WORKDIR /app
+
+FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
+WORKDIR /src
+COPY ["EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj", "EVCB_OCPP.WSServer/"]
+COPY ["SuperWebSocket/SuperWebSocket.csproj", "SuperWebSocket/"]
+COPY ["SocketBase/SuperSocket.SocketBase.csproj", "SocketBase/"]
+COPY ["SocketCommon/SuperSocket.Common.csproj", "SocketCommon/"]
+COPY ["SocketEngine/SuperSocket.SocketEngine.csproj", "SocketEngine/"]
+RUN dotnet restore "EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+COPY . .
+WORKDIR "/src/EVCB_OCPP.WSServer"
+RUN dotnet build "EVCB_OCPP.WSServer.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "EVCB_OCPP.WSServer.csproj" -c Release -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "EVCB_OCPP.WSServer.dll"]

+ 24 - 24
EVCB_OCPP.Server.sln

@@ -1,19 +1,19 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.30413.136
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33103.184
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EVCB_OCPP.WSServer", "EVCB_OCPP.WSServer\EVCB_OCPP.WSServer.csproj", "{DE0C1E9A-1EEE-42CC-8A91-73BF9056A7E7}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EVCB_OCPP.WSServer", "EVCB_OCPP.WSServer\EVCB_OCPP.WSServer.csproj", "{DE0C1E9A-1EEE-42CC-8A91-73BF9056A7E7}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestTool.RemoteTriggerAPP", "TestTool.RemoteTriggerAPP\TestTool.RemoteTriggerAPP.csproj", "{F39A3B1E-2B93-40E1-9C7B-8CEE2529BF52}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestTool.RemoteTriggerAPP", "TestTool.RemoteTriggerAPP\TestTool.RemoteTriggerAPP.csproj", "{F39A3B1E-2B93-40E1-9C7B-8CEE2529BF52}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperSocket.SocketBase.Net40", "SocketBase\SuperSocket.SocketBase.Net40.csproj", "{40B77789-EA11-4C05-8F52-86711D7BCAAF}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SuperWebSocket", "SuperWebSocket\SuperWebSocket.csproj", "{43C5BC98-FA2C-45D1-BF96-A299C05A72AE}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperSocket.Common.Net40", "SocketCommon\SuperSocket.Common.Net40.csproj", "{A24F4D38-BA9C-4FD6-95B7-4980DE36131A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SuperSocket.SocketBase", "SocketBase\SuperSocket.SocketBase.csproj", "{743510BD-A370-47A9-8264-0F30161EA9D0}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperSocket.SocketEngine.Net40", "SocketEngine\SuperSocket.SocketEngine.Net40.csproj", "{153FEF72-191C-43D9-BE71-2B351C7AC760}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SuperSocket.SocketEngine", "SocketEngine\SuperSocket.SocketEngine.csproj", "{D4A0E22B-8EAF-4CA5-AE1B-414508D71B62}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperWebSocket.NET45", "SuperWebSocket\SuperWebSocket.NET45.csproj", "{2DC79E40-BB70-4F6A-B378-905F2FBC6E97}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SuperSocket.Common", "SocketCommon\SuperSocket.Common.csproj", "{8241B98B-A7BF-4FBA-BD0B-B1536DDD1A72}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -29,22 +29,22 @@ Global
 		{F39A3B1E-2B93-40E1-9C7B-8CEE2529BF52}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{F39A3B1E-2B93-40E1-9C7B-8CEE2529BF52}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{F39A3B1E-2B93-40E1-9C7B-8CEE2529BF52}.Release|Any CPU.Build.0 = Release|Any CPU
-		{40B77789-EA11-4C05-8F52-86711D7BCAAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{40B77789-EA11-4C05-8F52-86711D7BCAAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{40B77789-EA11-4C05-8F52-86711D7BCAAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{40B77789-EA11-4C05-8F52-86711D7BCAAF}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A24F4D38-BA9C-4FD6-95B7-4980DE36131A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A24F4D38-BA9C-4FD6-95B7-4980DE36131A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A24F4D38-BA9C-4FD6-95B7-4980DE36131A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A24F4D38-BA9C-4FD6-95B7-4980DE36131A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{153FEF72-191C-43D9-BE71-2B351C7AC760}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{153FEF72-191C-43D9-BE71-2B351C7AC760}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{153FEF72-191C-43D9-BE71-2B351C7AC760}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{153FEF72-191C-43D9-BE71-2B351C7AC760}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2DC79E40-BB70-4F6A-B378-905F2FBC6E97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2DC79E40-BB70-4F6A-B378-905F2FBC6E97}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2DC79E40-BB70-4F6A-B378-905F2FBC6E97}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2DC79E40-BB70-4F6A-B378-905F2FBC6E97}.Release|Any CPU.Build.0 = Release|Any CPU
+		{43C5BC98-FA2C-45D1-BF96-A299C05A72AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{43C5BC98-FA2C-45D1-BF96-A299C05A72AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{43C5BC98-FA2C-45D1-BF96-A299C05A72AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{43C5BC98-FA2C-45D1-BF96-A299C05A72AE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{743510BD-A370-47A9-8264-0F30161EA9D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{743510BD-A370-47A9-8264-0F30161EA9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{743510BD-A370-47A9-8264-0F30161EA9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{743510BD-A370-47A9-8264-0F30161EA9D0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D4A0E22B-8EAF-4CA5-AE1B-414508D71B62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D4A0E22B-8EAF-4CA5-AE1B-414508D71B62}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D4A0E22B-8EAF-4CA5-AE1B-414508D71B62}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D4A0E22B-8EAF-4CA5-AE1B-414508D71B62}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8241B98B-A7BF-4FBA-BD0B-B1536DDD1A72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8241B98B-A7BF-4FBA-BD0B-B1536DDD1A72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8241B98B-A7BF-4FBA-BD0B-B1536DDD1A72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8241B98B-A7BF-4FBA-BD0B-B1536DDD1A72}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 0 - 0
EVCB_OCPP.WSServer/App.config → EVCB_OCPP.WSServer.backup/App.config


BIN
EVCB_OCPP.WSServer.backup/DLL/EVCB_OCPP.Domain.dll


BIN
EVCB_OCPP.WSServer.backup/DLL/EVCB_OCPP.Packet.dll


BIN
EVCB_OCPP.WSServer.backup/DLL/EVCB_OCPP20.Packet.dll


+ 0 - 0
EVCB_OCPP.WSServer/DLL/SuperSocket.Common.dll → EVCB_OCPP.WSServer.backup/DLL/SuperSocket.Common.dll


+ 0 - 0
EVCB_OCPP.WSServer/DLL/SuperSocket.SocketBase.dll → EVCB_OCPP.WSServer.backup/DLL/SuperSocket.SocketBase.dll


+ 0 - 0
EVCB_OCPP.WSServer/DLL/SuperSocket.SocketEngine.dll → EVCB_OCPP.WSServer.backup/DLL/SuperSocket.SocketEngine.dll


+ 0 - 0
EVCB_OCPP.WSServer/DLL/SuperWebSocket.dll → EVCB_OCPP.WSServer.backup/DLL/SuperWebSocket.dll


+ 65 - 0
EVCB_OCPP.WSServer.backup/Dto/ChargingPrice.cs

@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class ChargingPrice
+    {
+        private string _StartTime = "";
+        private string _EndTime = "";
+        public string StartTime
+        {
+            set
+            {
+                _StartTime = value;
+                if(!value.Contains("M"))
+                {                    
+                    DateTime dt = new DateTime(2021, 01, 01, int.Parse(_StartTime.Split(':')[0]), int.Parse(_StartTime.Split(':')[1]), 0, DateTimeKind.Utc);
+                    _StartTime = dt.ToString("hh:mm tt", new CultureInfo("en-us"));
+                }
+               
+            }
+            get
+            { return _StartTime; }
+        }
+
+        public string EndTime
+        {
+            set
+            {
+                _EndTime = value;
+                if (!value.Contains("M"))
+                {
+                    DateTime dt = new DateTime(2021, 01, 01, int.Parse(_EndTime.Split(':')[0]), int.Parse(_EndTime.Split(':')[1]), 0, DateTimeKind.Utc);
+                    _EndTime = dt.ToString("hh:mm tt", new CultureInfo("en-us"));
+                }
+                
+            }
+            get
+            { return _EndTime; }
+        }
+
+        public decimal Fee { set; get; }
+    }
+
+
+    public class ChargingBill
+    {
+        public string StartTime { set; get; }
+
+        public string EndTime { set; get; }
+
+        public decimal Total { set; get; }
+
+        public decimal PeriodEnergy { set; get; }
+
+        /// <summary>
+        /// 費率
+        /// </summary>
+        public decimal Fee { set; get; }
+    }
+}

+ 20 - 0
EVCB_OCPP.WSServer.backup/Dto/ConnectorErrorStauts.cs

@@ -0,0 +1,20 @@
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class ConnectorErrorStauts
+    {
+
+        public byte ConnectorId { get; set; }
+
+        public int Status { get; set; }
+
+        public int ChargePointErrorCodeId { get; set; }
+
+        public string ErrorInfo { get; set; }
+
+        public string VendorId { get; set; }
+
+        public string VendorErrorCode { get; set; }
+
+
+    }
+}

+ 25 - 0
EVCB_OCPP.WSServer.backup/Dto/ErrorDetails.cs

@@ -0,0 +1,25 @@
+using EVCB_OCPP.Packet.Messages.SubTypes;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using System;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class ErrorDetails
+    {
+        public string ChargeBoxId { set; get; }
+
+        public int ConnectorId { set; get; }
+
+        [JsonConverter(typeof(StringEnumConverter))]
+        public ChargePointErrorCode ErrorCode { set; get; }
+
+        public string Info { set; get; }
+
+        public string VendorId { set; get; }
+
+        public string VendorErrorCode { set; get; }
+
+        public DateTime OCcuredOn { set; get; }
+    }
+}

+ 21 - 0
EVCB_OCPP.WSServer.backup/Dto/ID_GetTxUserInfo.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class ID_GetTxUserInfo
+    {
+        public string VEMData { set; get; }
+
+        public string TxId { set; get; }
+
+        public Guid? SerialNo { set; get; }
+
+        public int ConnectorId { set; get; }
+
+        public DateTime StartTime { set; get; }
+    }
+}

+ 38 - 0
EVCB_OCPP.WSServer.backup/Dto/IdTokenInfo.cs

@@ -0,0 +1,38 @@
+using EVCB_OCPP.Packet.Messages.SubTypes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class IdTokenInfo
+    {
+
+        public IdTagInfo IdTagInfo { set; get; }
+
+        public decimal AccountBalance { set; get; }
+
+        public List<ChargePointFee> ChargePointFee { set; get; }
+    }
+
+
+    public class ChargePointFee
+    {
+        public bool IsAC { set; get; }       
+
+
+        public decimal? PerkWhFee { set; get; }
+
+        public decimal? PerHourFee { set; get; }
+
+
+        public decimal ParkingFee { set; get; }
+
+        public string Currency { set; get; }
+
+
+        public string DisplayMessage { set; get; }
+    }
+}

+ 37 - 0
EVCB_OCPP.WSServer.backup/Dto/StationFee.cs

@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class StationFee
+    {
+        /// <summary>
+        /// 收費方式 1: 以度計費 2:以小時計費
+        /// </summary>
+        public int BillingMethod { set; get; }
+
+        /// <summary>
+        /// 電樁顯示用費率 
+        /// </summary>
+        public string FeeName { set; get; }
+
+        /// <summary>
+        /// 停車費
+        /// </summary>
+        public decimal ParkingFee { set; get; }
+
+        /// <summary>
+        /// 幣別
+        /// </summary>
+        public string Currency { set; get; }
+
+        /// <summary>
+        /// 充電費率 以小時計費
+        /// </summary>
+        public decimal ChargingFeebyHour { set; get; }
+
+    }
+}

+ 18 - 0
EVCB_OCPP.WSServer.backup/Dto/TCCStationInfoDto.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class TCCStationInfoDto
+    {
+        public decimal Lat { set; get; }
+
+        public decimal Long { set; get; }
+
+        public string ZipCode { set; get; }
+
+    }
+}

+ 16 - 0
EVCB_OCPP.WSServer.backup/Dto/TCCWeatherDto.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class TCCWeatherDto
+    {
+        public int WeatherID { set; get; }
+
+
+        public int Temperature { set; get; }
+    }
+}

+ 17 - 0
EVCB_OCPP.WSServer.backup/Dto/TransactionEnergy.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Dto
+{
+    public class TransactionEnergy
+    {       
+
+        public int TxId { set; get; }
+
+
+        public Dictionary<string,decimal> PeriodEnergy { set; get; }
+    }
+}

+ 247 - 0
EVCB_OCPP.WSServer.backup/EVCB_OCPP.WSServer.csproj

@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{DE0C1E9A-1EEE-42CC-8A91-73BF9056A7E7}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>EVCB_OCPP.WSServer</RootNamespace>
+    <AssemblyName>EVCB_OCPP.WSServer</AssemblyName>
+    <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Dapper, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\Dapper.2.0.30\lib\net461\Dapper.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+    </Reference>
+    <Reference Include="EVCB_OCPP.Domain, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\EVCB_OCPP.Domain.dll</HintPath>
+    </Reference>
+    <Reference Include="EVCB_OCPP.Packet, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\EVCB_OCPP.Packet.dll</HintPath>
+    </Reference>
+    <Reference Include="EVCB_OCPP20.Packet, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\EVCB_OCPP20.Packet.dll</HintPath>
+    </Reference>
+    <Reference Include="log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
+      <HintPath>..\packages\log4net.2.0.3\lib\net40-full\log4net.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Binder, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.DependencyInjection, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.3.1.3\lib\net461\Microsoft.Extensions.DependencyInjection.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.3\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Http, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Http.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Http.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Logging.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Options, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Options.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Primitives, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Primitives.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
+      <HintPath>..\packages\NLog.4.6.6\lib\net45\NLog.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.IO.Compression" />
+    <Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Numerics" />
+    <Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.ServiceModel" />
+    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Transactions" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Dto\ChargingPrice.cs" />
+    <Compile Include="Dto\ErrorDetails.cs" />
+    <Compile Include="Dto\IdTokenInfo.cs" />
+    <Compile Include="Dto\ID_GetTxUserInfo.cs" />
+    <Compile Include="Dto\StationFee.cs" />
+    <Compile Include="Dto\TCCWeatherDto.cs" />
+    <Compile Include="Dto\TransactionEnergy.cs" />
+    <Compile Include="Dto\TCCStationInfoDto.cs" />
+    <Compile Include="Message\OCPP16MessageHandler.cs" />
+    <Compile Include="Message\OCPP20MessageHandler.cs" />
+    <Compile Include="Message\SecurityProfileHandler.cs" />
+    <Compile Include="Service\BusinessServiceFactory.cs" />
+    <Compile Include="Service\HttpClientService.cs" />
+    <Compile Include="Service\LoadingBalanceService.cs" />
+    <Compile Include="Service\LocalBusinessService.cs" />
+    <Compile Include="Service\OuterBusinessService.cs" />
+    <Compile Include="Dto\ConnectorErrorStauts.cs" />
+    <Compile Include="GlobalConfig.cs" />
+    <Compile Include="Helper\Convertor.cs" />
+    <Compile Include="Message\BasicMessageHandler.cs" />
+    <Compile Include="Message\CoreProfileHandler.cs" />
+    <Compile Include="Message\FirmwareManagementProfileHandler.cs" />
+    <Compile Include="Message\LocalAuthListManagementProfileHandler.cs" />
+    <Compile Include="Message\MessageResult.cs" />
+    <Compile Include="Message\NeedConfirmMessage.cs" />
+    <Compile Include="Message\RemoteTriggerHandler.cs" />
+    <Compile Include="Message\ReservationProfileHandler.cs" />
+    <Compile Include="Message\SmartChargingProfileHandler.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ProtalServer.cs" />
+    <Compile Include="Service\OuterHttpClient.cs" />
+    <Compile Include="SuperSocket.Command\ProcessCallCmd.cs" />
+    <Compile Include="SuperSocket.Command\ProcessCallErrorCmd.cs" />
+    <Compile Include="SuperSocket.Command\ProcessCallResultCmd.cs" />
+    <Compile Include="SuperSocket.Protocol\ClientData.cs" />
+    <Compile Include="SuperSocket.Protocol\OCPPLog.cs" />
+    <Compile Include="SuperSocket.Protocol\OCPPLogFactory.cs" />
+    <Compile Include="SuperSocket.Protocol\OCPPSubCommandParser.cs" />
+    <Compile Include="SuperSocket.Protocol\OCPPSubProtocol.cs" />
+    <Compile Include="SuperSocket.Protocol\OCPPWSServer.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config">
+      <SubType>Designer</SubType>
+    </None>
+    <Content Include="DLL\EVCB_OCPP20.Packet.dll" />
+    <Content Include="DLL\SuperSocket.Common.dll" />
+    <Content Include="DLL\SuperSocket.SocketBase.dll" />
+    <Content Include="DLL\SuperSocket.SocketEngine.dll" />
+    <Content Include="DLL\SuperWebSocket.dll" />
+    <Content Include="NLog.config">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <SubType>Designer</SubType>
+    </Content>
+    <None Include="NLog.xsd">
+      <SubType>Designer</SubType>
+    </None>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="DLL\EVCB_OCPP.Domain.dll" />
+    <Content Include="DLL\EVCB_OCPP.Packet.dll" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\SocketBase\SuperSocket.SocketBase.Net40.csproj">
+      <Project>{40b77789-ea11-4c05-8f52-86711d7bcaaf}</Project>
+      <Name>SuperSocket.SocketBase.Net40</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\SocketCommon\SuperSocket.Common.Net40.csproj">
+      <Project>{a24f4d38-ba9c-4fd6-95b7-4980de36131a}</Project>
+      <Name>SuperSocket.Common.Net40</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\SocketEngine\SuperSocket.SocketEngine.Net40.csproj">
+      <Project>{153fef72-191c-43d9-be71-2b351c7ac760}</Project>
+      <Name>SuperSocket.SocketEngine.Net40</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\SuperWebSocket\SuperWebSocket.NET45.csproj">
+      <Project>{2dc79e40-bb70-4f6a-b378-905f2fbc6e97}</Project>
+      <Name>SuperWebSocket.NET45</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include=".NETFramework,Version=v4.7.1">
+      <Visible>False</Visible>
+      <ProductName>Microsoft .NET Framework 4.7.1 %28x86 和 x64%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>GitVersion.exe $(ProjectDir) /updateassemblyinfo</PreBuildEvent>
+  </PropertyGroup>
+</Project>

+ 6 - 0
EVCB_OCPP.WSServer.backup/GitVersion.yml

@@ -0,0 +1,6 @@
+assembly-versioning-scheme: MajorMinorPatch
+assembly-informational-format: '{ShortSha}'
+next-version: 0.1.0
+branches: {}
+ignore:
+  sha: []

+ 143 - 0
EVCB_OCPP.WSServer.backup/GlobalConfig.cs

@@ -0,0 +1,143 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+
+namespace EVCB_OCPP.WSServer
+{
+    public static class GlobalConfig
+    {
+        public static List<string> ConfigKeys = new List<string>()
+        {
+            "WSPort",
+            "WSSPort",
+            "OCPP20_WSUrl",
+            "OCPP20_WSSUrl"
+        };
+
+        public static  string UTC_DATETIMEFORMAT = "yyyy-MM-dd'T'HH':'mm':'ss'Z'";
+
+        public static string TCC_API_URL = string.Empty;
+
+        public static string TCC_SALTKEY = string.Empty;
+
+        public static string OCPP20_WSUrl = string.Empty;
+
+        public static string OCPP20_WSSUrl = string.Empty;
+
+        public static JsonSerializerSettings JSONSERIALIZER_FORMAT = new JsonSerializerSettings()
+        {
+            NullValueHandling = NullValueHandling.Ignore,
+            Formatting = Formatting.None,
+            DateFormatString = UTC_DATETIMEFORMAT
+        };
+
+        /// <summary>
+        /// 預設心跳間隔時間 單位:秒
+        /// </summary>
+        private static int DEFAULT_HEARTBEAT_INTERVAL = 60;
+
+
+
+        /// <summary>
+        ///WS Port
+        /// </summary>
+        private static int WS_Port = 2012;
+
+
+        /// <summary>
+        ///WSS Port
+        /// </summary>
+        private static int WSS_Port = 2013;
+
+        /// <summary>
+        /// Load setting from app.config 
+        /// </summary>
+        public static bool LoadAPPConfig()
+        {
+            bool result = false;
+            string key = string.Empty;
+            try
+            {
+
+                for (int i = 0; i < ConfigKeys.Count; i++)
+                {
+                    key = ConfigKeys[i];
+                    switch (key)
+                    {
+                        case "WSPort":// convert to int type                       
+                            {
+                                var value = ConfigurationManager.AppSettings[key];
+
+                                WS_Port = Convert.ToInt32(value);
+                            }
+                            break;
+                        case "WSSPort":
+                            {
+                                var value = ConfigurationManager.AppSettings[key];
+
+                                WSS_Port = Convert.ToInt32(value);
+                            }
+                            break;
+                        case "OCPP20_WSUrl":// convert to int type                       
+                            {
+                                var value = ConfigurationManager.AppSettings[key];
+
+                                OCPP20_WSUrl = value;
+                            }
+                            break;
+                        case "OCPP20_WSSUrl":// convert to int type                       
+                            {
+                                var value = ConfigurationManager.AppSettings[key];
+
+                                OCPP20_WSSUrl = value;
+                            }
+                            break;
+                        default://convert to string type                             
+                            break;
+
+                    }
+                }
+                result = true;
+
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(key + " Load from APPConfig " + ex.ToString());
+
+            }
+
+            return result;
+        }
+
+
+
+        public static int GetWS_Port()
+        {
+            return WS_Port;
+        }
+
+
+        public static int GetWSS_Port()
+        {
+            return WSS_Port;
+        }
+
+        public static int GetHEARTBEAT_INTERVAL()
+        {
+            return DEFAULT_HEARTBEAT_INTERVAL;
+        }
+
+        public static readonly int DB_DefaultConnectionTimeout = 60;
+   
+        /// <summary>
+        /// 預設 Null的 DateTime 
+        /// </summary>
+        public static DateTime DefaultNullTime = new DateTime(1991, 1, 1);
+
+
+
+
+
+    }
+}

+ 24 - 0
EVCB_OCPP.WSServer.backup/Helper/Convertor.cs

@@ -0,0 +1,24 @@
+using EVCB_OCPP.Packet.Features;
+using System;
+
+namespace EVCB_OCPP.WSServer.Helper
+{
+    public static class Convertor
+    {
+        public static Actions GetAction(string action)
+        {
+            Actions result = Actions.None;
+            Enum.TryParse<Actions>(action, out result);
+            return result;
+        }
+
+        public static EVCB_OCPP20.Packet.Features.Actions GetActionby20(string action)
+        {
+            EVCB_OCPP20.Packet.Features.Actions result = EVCB_OCPP20.Packet.Features.Actions.None;
+            Enum.TryParse<EVCB_OCPP20.Packet.Features.Actions>(action, out result);
+            return result;
+        }
+
+
+    }
+}

+ 155 - 0
EVCB_OCPP.WSServer.backup/Message/BasicMessageHandler.cs

@@ -0,0 +1,155 @@
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+using NLog;
+using OCPPServer.Protocol;
+
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    /// <summary>
+    /// 實現 OCPP 基本傳送規範,
+    /// 1.訊息 基本格式,將訊息包裝成 Call 、CallResult、CallError 三種格式
+    /// 2.OCPP 定義的傳送規則:交易相關的訊息必須依照時序性傳送,一個傳完才能接著送下一個(忽略規則 由Center System定義)
+    /// </summary>
+    internal class BasicMessageHandler
+    {
+        static protected ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+
+        #region 傳送 or 解析訊息需要欄位
+        private const int INDEX_MESSAGEID = 0;
+        private const int INDEX_UNIQUEID = 1;
+        internal const int TYPENUMBER_CALL = 2;
+        private const int INDEX_CALL_ACTION = 2;
+        private const int INDEX_CALL_PAYLOAD = 3;
+
+        internal const int TYPENUMBER_CALLRESULT = 3;
+        private const int INDEX_CALLRESULT_PAYLOAD = 2;
+
+        internal const int TYPENUMBER_CALLERROR = 4;
+        private const int INDEX_CALLERROR_ERRORCODE = 2;
+        private const int INDEX_CALLERROR_DESCRIPTION = 3;
+        private const int INDEX_CALLERROR_PAYLOAD = 4;
+
+        private const string CALL_FORMAT = "[2,\"{0}\",\"{1}\",{2}]";
+        private const string CALLRESULT_FORMAT = "[3,\"{0}\",{1}]";
+        private const string CALLERROR_FORMAT = "[4,\"{0}\",\"{1}\",\"{2}\",{3}]";
+        private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+        private const string DATE_FORMAT_WITH_MS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+        #endregion
+
+        private OCPP16MessageHandler _ocpp16Handler = new OCPP16MessageHandler();
+        private OCPP20MessageHandler _ocpp20Handler = new OCPP20MessageHandler();
+
+        /// <summary>
+        /// 將收到的封包做基本的拆解分成 Call 、CallResult、CallError
+        /// </summary>
+        /// <param name="client"></param>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        internal MessageResult AnalysisReceiveData(ClientData client, string data)
+        {
+            MessageResult result = null;
+            if (!client.ISOCPP20)
+            {
+                result = _ocpp16Handler.AnalysisReceiveData(client, data);
+            }
+            else
+            {
+                result = _ocpp20Handler.AnalysisReceiveData(client, data);
+            }
+
+            return result;
+        }
+
+
+        static internal string GenerateCallError(string uniqueId, string errorCode, string errorDescription)
+        {
+
+            string msg = string.Format(CALLERROR_FORMAT, uniqueId, errorCode, errorDescription, "{}");
+            return msg;
+
+        }
+
+        static internal string GenerateConfirmation(string uniqueId, IConfirmation confirmation)
+        {
+            string msg = string.Empty;
+            if (confirmation != null && confirmation.Validate())
+            {
+
+                msg = string.Format(CALLRESULT_FORMAT, uniqueId, JsonConvert.SerializeObject(confirmation, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }));
+            }
+            else
+            {
+                logger.Error(string.Format("confirmation is null  or InVaild in GenerateConfirmation Method"), "Warning");
+            }
+            return msg;
+        }
+        static internal string GenerateConfirmationofOCPP20(string uniqueId, EVCB_OCPP20.Packet.Messages.IConfirmation confirmation)
+        {
+            string msg = string.Empty;
+            if (confirmation != null && confirmation.Validate())
+            {
+
+                msg = string.Format(CALLRESULT_FORMAT, uniqueId, JsonConvert.SerializeObject(confirmation, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }));
+            }
+            else
+            {
+                logger.Error(string.Format("confirmation is null  or InVaild in GenerateConfirmation Method"), "Warning");
+            }
+            return msg;
+        }
+
+        static internal string GenerateRequest(string uniqueId, string action, IRequest request)
+        {
+            string msg = string.Empty;
+            if (request != null && request.Validate())
+            {
+
+                msg = string.Format(CALL_FORMAT, uniqueId, action, JsonConvert.SerializeObject(request, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }));
+            }
+            else
+            {
+                if (action == Actions.ChangeConfiguration.ToString())
+                {
+                    if(!request.Validate())
+                    {
+                        logger.Error("!Validate", "Warning");
+                    }
+
+                    if (request == null)
+                    {
+                        logger.Error("!NULL", "Warning");
+                    }
+
+                }
+
+                logger.Error(string.Format("confirmation is null  or InVaild in GenerateRequest Method "+ action), "Warning");
+            }
+            return msg;
+        }
+
+        static internal string GenerateRequestofOCPP20(string uniqueId, string action, EVCB_OCPP20.Packet.Messages.IRequest request)
+        {
+            string msg = string.Empty;
+            if (request != null && request.Validate())
+            {
+
+                msg = string.Format(CALL_FORMAT, uniqueId, action, JsonConvert.SerializeObject(request, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }));
+            }
+            else
+            {
+                logger.Error(string.Format("confirmation is null  or InVaild in GenerateRequest Method"), "Warning");
+            }
+            return msg;
+        }
+
+        static internal string GenerateDestroyRequest(string uniqueId, string action, string request)
+        {
+
+
+            return string.Format(CALL_FORMAT, uniqueId, action, request);
+        }
+    }
+}

+ 1656 - 0
EVCB_OCPP.WSServer.backup/Message/CoreProfileHandler.cs

@@ -0,0 +1,1656 @@
+using Dapper;
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Domain.Models.Database;
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.Core;
+using EVCB_OCPP.Packet.Messages.SubTypes;
+using EVCB_OCPP.WSServer.Dto;
+using EVCB_OCPP.WSServer.Service;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using NLog;
+using OCPPPackage.Profiles;
+using OCPPServer.Protocol;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.Entity;
+using System.Data.SqlClient;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    public class ID_CreditDeductResult
+    {
+        public int txId { set; get; }
+
+        public string creditNo { set; get; }
+
+
+        public bool deductResult { set; get; }
+
+        public bool isDonateInvoice { set; get; }
+
+
+        public decimal amount { set; get; }
+
+        public string approvalNo { set; get; }
+
+    }
+
+    public class ID_ReaderStatus
+    {
+        public int ConnectorId { set; get; }
+
+        public string creditNo { set; get; }
+
+
+        public string SerialNo { set; get; }
+
+        public int readerStatus { set; get; }
+
+        public string VEMData { set; get; }
+
+        public DateTime Timestamp { set; get; }
+
+
+
+
+    }
+
+    internal partial class ProfileHandler
+    {
+        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+        private OuterHttpClient httpClient = new OuterHttpClient();
+     
+        async internal Task<MessageResult> ExecuteCoreRequest(Actions action, ClientData session, IRequest request)
+        {
+            Stopwatch watch = new Stopwatch();
+            if (action == Actions.Heartbeat)
+            {
+                watch.Start();
+            }
+            MessageResult result = new MessageResult() { Success = false };
+
+            try
+            {
+                switch (action)
+                {
+                    case Actions.DataTransfer:
+                        {
+                            DataTransferRequest _request = request as DataTransferRequest;
+                            var confirm = new DataTransferConfirmation() { status = DataTransferStatus.UnknownMessageId };
+
+                            if (_request.messageId == "ID_CreditDeductResult")
+                            {
+
+                                var creditDeductResult = JsonConvert.DeserializeObject<ID_CreditDeductResult>(_request.data);
+                                if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
+                                {
+                                    var report = new
+                                    {
+                                        ChargeBoxId = session.ChargeBoxId,
+                                        IsDonateInvoice = creditDeductResult.isDonateInvoice,
+                                        CreditNo = creditDeductResult.creditNo,
+                                        DeductResult = creditDeductResult.deductResult,
+                                        SessionId = creditDeductResult.txId,
+                                        ApprovalNo = creditDeductResult.approvalNo,
+                                        TotalCost = creditDeductResult.amount,
+
+                                    };
+
+                                    var response = await httpClient.Post(GlobalConfig.TCC_API_URL + "prepare_issue_invoice", new Dictionary<string, string>()
+                                        {
+                                            { "PartnerId",session.CustomerId.ToString()}
+
+                                        }, report, GlobalConfig.TCC_SALTKEY);
+
+                                    logger.Debug(JsonConvert.SerializeObject(response));
+                                }
+
+
+                                confirm.status = DataTransferStatus.Accepted;
+                                confirm.data = JsonConvert.SerializeObject(new { txId = creditDeductResult.txId, creditNo = creditDeductResult.creditNo, msgId = _request.messageId });
+                            }
+                            if (_request.messageId == "ID_ReaderStatus")
+                            {
+                                if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
+                                {
+                                    var preauth_status = JsonConvert.DeserializeObject<ID_ReaderStatus>(_request.data);
+                                    var report = new
+                                    {
+                                        ChargeBoxId = session.ChargeBoxId,
+                                        ConnectorId = preauth_status.ConnectorId,
+                                        CreditNo = preauth_status.creditNo,
+                                        ReaderStatus = preauth_status.readerStatus,
+                                        SerialNo = preauth_status.SerialNo,
+                                        VEMData = preauth_status.VEMData,
+                                        Timestamp = preauth_status.Timestamp
+
+                                    };
+
+                                    var response = await httpClient.Post(GlobalConfig.TCC_API_URL + "preauth_status", new Dictionary<string, string>()
+                                        {
+                                            { "PartnerId",session.CustomerId.ToString()}
+
+                                        }, report, GlobalConfig.TCC_SALTKEY);
+
+
+                                    confirm.status = DataTransferStatus.Accepted;
+                                }
+                            }
+                            if (_request.messageId == "ID_OCMF")
+                            {
+                                JObject jo = JObject.Parse(_request.data);
+
+                                logger.Debug(string.Format("{0}\r\n{1}\r\n{2}", jo["txId"].Value<int>(), jo["dataString"].Value<string>(), jo["publicKey"].Value<string>()));
+
+                                using (var db = new MainDBContext())
+                                {
+                                    db.OCMF.Add(new OCMF()
+                                    {
+                                        TransactionId = jo["txId"].Value<int>(),
+                                        DataString = jo["dataString"].Value<string>(),
+                                        PublicKey = jo["publicKey"].Value<string>()
+                                    });
+
+                                    await db.SaveChangesAsync();
+                                }
+
+
+                                confirm.status = DataTransferStatus.Accepted;
+                                confirm.data = JsonConvert.SerializeObject(new { txId = jo["txId"].Value<int>(), msgId = _request.messageId });
+                            }
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    case Actions.BootNotification:
+                        {
+                            BootNotificationRequest _request = request as BootNotificationRequest;
+                            int heartbeat_interval = GlobalConfig.GetHEARTBEAT_INTERVAL();
+                            using (var db = new MainDBContext())
+                            {
+                                var _machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+                                _machine.ChargeBoxSerialNumber = string.IsNullOrEmpty(_request.chargeBoxSerialNumber) ? string.Empty : _request.chargeBoxSerialNumber;
+                                _machine.ChargePointSerialNumber = string.IsNullOrEmpty(_request.chargePointSerialNumber) ? string.Empty : _request.chargePointSerialNumber;
+                                _machine.ChargePointModel = string.IsNullOrEmpty(_request.chargePointModel) ? string.Empty : _request.chargePointModel;
+                                _machine.ChargePointVendor = string.IsNullOrEmpty(_request.chargePointVendor) ? string.Empty : _request.chargePointVendor;
+                                _machine.FW_CurrentVersion = string.IsNullOrEmpty(_request.firmwareVersion) ? string.Empty : _request.firmwareVersion;
+                                //_machine.Iccid = string.IsNullOrEmpty(_request.iccid) ? string.Empty : _request.iccid;
+                                _machine.Iccid = DateTime.UtcNow.ToString("yy-MM-dd HH:mm");
+                                _machine.Imsi = string.IsNullOrEmpty(_request.imsi) ? string.Empty : _request.imsi;
+                                _machine.MeterSerialNumber = string.IsNullOrEmpty(_request.meterSerialNumber) ? string.Empty : _request.meterSerialNumber;
+                                _machine.MeterType = string.IsNullOrEmpty(_request.meterType) ? string.Empty : _request.meterType;
+
+                                db.SaveChanges();
+
+
+
+                                var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.HeartbeatInterval)
+                                    .Select(x => x.ConfigureSetting).FirstOrDefault();
+
+                                if (configVaule != null)
+                                {
+                                    int.TryParse(configVaule, out heartbeat_interval);
+                                }
+                            }
+                            var confirm = new BootNotificationConfirmation() { currentTime = DateTime.UtcNow, interval = session.IsPending ? heartbeat_interval : 5, status = session.IsPending ? Packet.Messages.SubTypes.RegistrationStatus.Accepted : RegistrationStatus.Pending };
+
+                            session.IsPending = !session.IsPending;
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    case Actions.StatusNotification:
+                        {
+                            //只保留最新上報狀況
+                            StatusNotificationRequest _request = request as StatusNotificationRequest;
+                            int preStatus = 0;
+                            using (var db = new MainDBContext())
+                            {
+                                var _oldStatus = db.ConnectorStatus.Where(x => x.ChargeBoxId == session.ChargeBoxId
+                              && x.ConnectorId == _request.connectorId).AsNoTracking().FirstOrDefault();
+
+
+                                if (_oldStatus != null && (_request.status != (ChargePointStatus)_oldStatus.Status || _request.status == ChargePointStatus.Faulted))
+                                {
+
+                                    preStatus = _oldStatus.Status;
+
+                                    db.Configuration.AutoDetectChangesEnabled = false;
+                                    db.Configuration.ValidateOnSaveEnabled = false;
+                                    db.ConnectorStatus.Attach(_oldStatus);
+
+
+                                    _oldStatus.CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow;
+                                    _oldStatus.Status = (int)_request.status;
+                                    _oldStatus.ChargePointErrorCodeId = (int)_request.errorCode;
+                                    _oldStatus.ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info;
+                                    _oldStatus.VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId;
+                                    _oldStatus.VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode;
+
+
+                                    db.Entry(_oldStatus).Property(x => x.CreatedOn).IsModified = true;
+                                    db.Entry(_oldStatus).Property(x => x.Status).IsModified = true;
+                                    db.Entry(_oldStatus).Property(x => x.ChargePointErrorCodeId).IsModified = true;
+                                    db.Entry(_oldStatus).Property(x => x.ErrorInfo).IsModified = true;
+                                    db.Entry(_oldStatus).Property(x => x.VendorId).IsModified = true;
+                                    db.Entry(_oldStatus).Property(x => x.VendorErrorCode).IsModified = true;
+
+
+                                }
+
+                                if (_oldStatus == null)
+                                {
+                                    var _currentStatus = new Domain.Models.Database.ConnectorStatus()
+                                    {
+                                        ChargeBoxId = session.ChargeBoxId,
+                                        ConnectorId = (byte)_request.connectorId,
+                                        CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow,
+                                        Status = (int)_request.status,
+                                        ChargePointErrorCodeId = (int)_request.errorCode,
+                                        ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
+                                        VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId,
+                                        VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
+                                        Id = Guid.NewGuid().ToString()
+                                    };
+                                    db.ConnectorStatus.Add(_currentStatus);
+
+                                }
+                                if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted)
+                                {
+                                    db.MachineError.Add(new MachineError()
+                                    {
+                                        ConnectorId = (byte)_request.connectorId,
+                                        CreatedOn = _request.timestamp.HasValue ? _request.timestamp.Value : DateTime.UtcNow,
+                                        Status = (int)_request.status,
+                                        ChargeBoxId = session.ChargeBoxId,
+                                        ErrorCodeId = (int)_request.errorCode,
+                                        ErrorInfo = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
+                                        PreStatus = _oldStatus == null ? -1 : preStatus,
+                                        VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
+                                        VendorId = string.IsNullOrEmpty(_request.vendorId) ? string.Empty : _request.vendorId
+                                    });
+                                }
+                                db.SaveChanges();
+                            }
+
+
+                            if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted)
+                            {
+                                var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+                                var notification = businessService.NotifyFaultStatus(new ErrorDetails()
+                                {
+                                    ChargeBoxId = session.ChargeBoxId,
+                                    ConnectorId = _request.connectorId,
+                                    ErrorCode = _request.errorCode,
+                                    Info = string.IsNullOrEmpty(_request.info) ? string.Empty : _request.info,
+                                    OCcuredOn = _request.timestamp ?? DateTime.UtcNow,
+                                    VendorErrorCode = string.IsNullOrEmpty(_request.vendorErrorCode) ? string.Empty : _request.vendorErrorCode,
+
+                                });
+                            }
+
+                            var confirm = new StatusNotificationConfirmation() { };
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    case Actions.Heartbeat:
+                        {
+
+                            var confirm = new HeartbeatConfirmation() { currentTime = DateTime.UtcNow };
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    case Actions.MeterValues:
+                        {
+
+                            MeterValuesRequest _request = request as MeterValuesRequest;
+
+                            if (_request.meterValue.Count > 0)
+                            {
+
+
+                                using (var db = new MeterValueDBContext())
+                                {
+                                    foreach (var item in _request.meterValue)
+                                    {
+                                        if (_request.transactionId.HasValue)
+                                        {
+                                            decimal meterStart = 0;
+                                            var energy_Register = item.sampledValue.Where(x => x.measurand == Measurand.Energy_Active_Import_Register).FirstOrDefault();
+
+                                            if (energy_Register != null)
+                                            {
+                                                decimal energyRegister = decimal.Parse(energy_Register.value);
+                                                energyRegister = energy_Register.unit.Value == UnitOfMeasure.kWh ? decimal.Multiply(energyRegister, 1000) : energyRegister;
+
+
+                                                using (var maindb = new MainDBContext())
+                                                {
+                                                    meterStart = maindb.TransactionRecord.Where(x => x.Id == _request.transactionId.Value).Select(x => x.MeterStart).FirstOrDefault();
+                                                }
+
+                                                item.sampledValue.Add(new SampledValue()
+                                                {
+                                                    context = ReadingContext.Sample_Periodic,
+                                                    format = ValueFormat.Raw,
+                                                    location = Location.Outlet,
+                                                    phase = item.sampledValue.Where(x => x.measurand == Measurand.Energy_Active_Import_Register).Select(x => x.phase).FirstOrDefault(),
+                                                    unit = UnitOfMeasure.Wh,
+                                                    measurand = Measurand.TotalEnergy,
+                                                    value = decimal.Subtract(energyRegister, meterStart).ToString()
+                                                });
+                                            }
+
+                                        }
+
+                                        foreach (var sampleVaule in item.sampledValue)
+                                        {
+
+                                            decimal value = Convert.ToDecimal(sampleVaule.value);
+
+                                            string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," +
+                         "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId";
+
+                                            List<SqlParameter> parameter = new List<SqlParameter>
+                                        {
+                                              new SqlParameter("ChargeBoxId",session.ChargeBoxId),
+                                              new SqlParameter("ConnectorId",  (byte)_request.connectorId),
+                                              new SqlParameter("Value",value),
+                                              new SqlParameter("CreatedOn",item.timestamp),
+                                              new SqlParameter("ContextId",sampleVaule.context.HasValue ? (int)sampleVaule.context : 0),
+                                              new SqlParameter("FormatId",sampleVaule.format.HasValue ? (int)sampleVaule.format : 0),
+                                              new SqlParameter("MeasurandId",sampleVaule.measurand.HasValue ? (int)sampleVaule.measurand : 0),
+                                              new SqlParameter("PhaseId",sampleVaule.phase.HasValue ? (int)sampleVaule.phase : 0),
+                                              new SqlParameter("LocationId",sampleVaule.location.HasValue ? (int)sampleVaule.location : 0),
+                                              new SqlParameter("UnitId",sampleVaule.unit.HasValue ? (int)sampleVaule.unit : 0),
+                                              new SqlParameter("TransactionId",_request.transactionId.HasValue?_request.transactionId:-1),
+                                          };
+
+
+                                            db.Database.ExecuteSqlCommand(sp, parameter.ToArray());
+
+
+
+
+                                        }
+
+                                    }
+                                }
+                            }
+
+                            //  if (energy_kwh > 0)
+                            {
+                                try
+                                {
+                                    if (session.IsBilling)
+                                        if (session.IsBilling)
+                                        {
+                                            using (var db = new MainDBContext())
+                                            {
+                                                db.ServerMessage.Add(new ServerMessage()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    CreatedBy = "Server",
+                                                    CreatedOn = DateTime.UtcNow,
+                                                    OutAction = Actions.DataTransfer.ToString(),
+                                                    OutRequest = JsonConvert.SerializeObject(
+                                                            new DataTransferRequest()
+                                                            {
+                                                                messageId = "ID_TxEnergy",
+                                                                vendorId = "Phihong Technology",
+                                                                data = JsonConvert.SerializeObject(new { txId = _request.transactionId, ConnectorId = _request.connectorId })
+                                                            },
+                                                            new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                    SerialNo = Guid.NewGuid().ToString(),
+                                                    InMessage = string.Empty
+
+                                                });
+
+                                                db.SaveChanges();
+                                            }
+                                        }
+
+
+                                }
+                                catch (Exception ex)
+                                {
+
+                                    Console.WriteLine(string.Format("{0} :{1}", session.ChargeBoxId + " RunningCost", ex.Message));
+
+                                }
+
+                            }
+
+                            var confirm = new MeterValuesConfirmation() { };
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    case Actions.StartTransaction:
+                        {
+
+                            StartTransactionRequest _request = request as StartTransactionRequest;
+
+                            int _transactionId = -1;
+
+                            var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+
+                            var _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
+                            if (_request.idTag != "Backend")
+                            {
+                                var authorization_result = await businessService.Authorize(session.ChargeBoxId, _request.idTag);
+                                _idTagInfo = authorization_result.IdTagInfo;
+
+                                if (_idTagInfo.status == AuthorizationStatus.Accepted && authorization_result.ChargePointFee != null)
+                                {
+                                    var price = authorization_result.ChargePointFee.Where(x => x.IsAC == session.IsAC).First();
+                                    if (price != null)
+                                    {
+
+                                        if (session.UserPrices.ContainsKey(_request.idTag))
+                                        {
+                                            session.UserPrices[_request.idTag] = price.PerkWhFee.HasValue ? JsonConvert.SerializeObject(new List<ChargingPrice>() { new ChargingPrice() { StartTime = "00:00", EndTime = "23:59", Fee = price.PerkWhFee.Value } }) : price.PerHourFee.Value.ToString();
+                                            session.UserPrices[_request.idTag] += "|+" + authorization_result.AccountBalance + "+" + "&" + price.ParkingFee + "&|" + price.Currency;
+
+                                        }
+                                        else
+                                        {
+                                            session.UserPrices.Add(_request.idTag, price.PerkWhFee.HasValue ? JsonConvert.SerializeObject(new List<ChargingPrice>() { new ChargingPrice() { StartTime = "00:00", EndTime = "23:59", Fee = price.PerkWhFee.Value } }) : price.PerHourFee.Value.ToString());
+                                            session.UserPrices[_request.idTag] += "|+" + authorization_result.AccountBalance + "+" + "&" + price.ParkingFee + "&|" + price.Currency;
+
+                                        }
+                                    }
+                                }
+
+                            }
+
+                            //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電
+                            if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && _idTagInfo.status == AuthorizationStatus.ConcurrentTx)
+                            {
+                                _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
+                            }
+
+                            string accountBalance = "0";
+                            if (session.CustomerId.ToString().ToUpper() == "10C7F5BD-C89A-4E2A-8611-B617E0B41A73")
+                            {
+                                using (SqlConnection conn = new SqlConnection(webConnectionString))
+                                {
+                                    var parameters = new DynamicParameters();
+                                    parameters.Add("@IdTag", _request.idTag, DbType.String, ParameterDirection.Input);
+                                    string strSql = "select parentIdTag from [dbo].[LocalListDetail]  where ListId = 27 and IdTag=@IdTag; ";
+                                    accountBalance = conn.ExecuteScalar<string>(strSql, parameters);
+                                }
+                            }
+
+
+                            using (var db = new MainDBContext())
+                            {
+                                var _CustomerId = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).Include(x => x.Customer).
+                                     Select(x => x.CustomerId).FirstOrDefault();
+
+                                var _existedTx = db.TransactionRecord.Where(x => x.CustomerId == _CustomerId && x.ChargeBoxId == session.ChargeBoxId
+                                   && x.ConnectorId == _request.connectorId && x.StartTime == _request.timestamp).Select(C => new { C.Id }).AsNoTracking().FirstOrDefault();
+                                TransactionRecord _newTransaction = new TransactionRecord();
+
+
+                                if (_existedTx == null)
+                                {
+                                    _newTransaction = new TransactionRecord()
+                                    {
+                                        ChargeBoxId = session.ChargeBoxId,
+                                        ConnectorId = (byte)_request.connectorId,
+                                        CreatedOn = DateTime.UtcNow,
+                                        StartIdTag = _request.idTag,
+                                        MeterStart = _request.meterStart,
+                                        CustomerId = _CustomerId,
+                                        StartTime = _request.timestamp.ToUniversalTime(),
+                                        ReservationId = _request.reservationId.HasValue ? _request.reservationId.Value : 0,
+                                    };
+
+                                    if (session.UserPrices.ContainsKey(_request.idTag))
+                                    {
+                                        _newTransaction.Fee = !session.IsBilling ? string.Empty : session.UserPrices[_request.idTag];
+
+                                    }
+                                    else
+                                    {
+                                        _newTransaction.Fee = !session.IsBilling ? string.Empty : session.BillingMethod == 1 ? JsonConvert.SerializeObject(session.ChargingPrices) : session.ChargingFeebyHour.ToString();
+                                        _newTransaction.Fee += !session.IsBilling ? string.Empty : "|+" + accountBalance + "+" + "&" + session.ParkingFee + "&|" + session.Currency;
+                                    }
+
+                                    db.TransactionRecord.Add(_newTransaction);
+
+                                    db.SaveChanges();
+
+                                    _transactionId = _newTransaction.Id;
+                                    logger.Info("***************************************************** ");
+                                    logger.Info(string.Format("{0} :TransactionId {1} ", session.ChargeBoxId, _newTransaction.Id));
+                                    logger.Info("***************************************************** ");
+                                }
+                                else
+                                {
+                                    _transactionId = _existedTx.Id;
+                                    logger.Error("Duplication ***************************************************** " + _existedTx.Id);
+                                }
+                            }
+
+
+                            var confirm = new StartTransactionConfirmation()
+                            {
+                                idTagInfo = _idTagInfo,
+                                transactionId = _transactionId
+                            };
+
+
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    case Actions.StopTransaction:
+                        {
+                            StopTransactionRequest _request = request as StopTransactionRequest;
+
+                            int _ConnectorId = 0;
+
+                            var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+
+                            var _idTagInfo = string.IsNullOrEmpty(_request.idTag) ? null : (_request.idTag == "Backend" ?
+                                new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } : (await businessService.Authorize(session.ChargeBoxId, _request.idTag)).IdTagInfo);
+
+                            //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電
+                            if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && _idTagInfo != null && _idTagInfo.status == AuthorizationStatus.ConcurrentTx)
+                            {
+                                _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
+                            }
+                            try
+                            {                              
+                                using (var db = new MainDBContext())
+                                {
+                                    var transaction = db.TransactionRecord.Where(x => x.Id == _request.transactionId
+                                     && x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+
+
+
+                                    //遠傳太久以前的停止充電 直接拒絕 避免電樁持續重送~~~~~~~
+                                    if (_request.timestamp < new DateTime(2021, 11, 1))
+                                    {
+                                        var confirm = new StopTransactionConfirmation()
+                                        {
+                                            idTagInfo = new IdTagInfo()
+                                            {
+                                                status = AuthorizationStatus.Invalid
+                                            }
+
+                                        };
+
+                                        result.Message = confirm;
+                                        result.Success = true;
+                                        return result;
+                                    }
+
+
+                                    if (transaction != null)
+                                    {
+                                        var confirm = new StopTransactionConfirmation()
+                                        {
+                                            idTagInfo = _idTagInfo
+
+                                        };
+
+                                        //Avoid rewrite transaction data
+                                        if (transaction.StopTime != GlobalConfig.DefaultNullTime)
+                                        {
+                                            result.Message = confirm;
+                                            result.Success = true;
+                                            return result;
+                                        }
+
+                                        _ConnectorId = transaction.ConnectorId;
+                                        transaction.MeterStop = _request.meterStop;
+                                        transaction.StopTime = _request.timestamp.ToUniversalTime();
+                                        transaction.StopReasonId = _request.reason.HasValue ? (int)_request.reason.Value : 0;
+                                        transaction.StopReason = _request.reason.HasValue ? _request.reason.Value.ToString() : Reason.Local.ToString();
+                                        transaction.StopIdTag = _request.idTag;
+                                        transaction.Receipt = string.Empty;
+                                        transaction.Cost = session.IsBilling ? -1 : 0;
+
+                                        if (_request.transactionData != null && _request.transactionData.Count > 0)
+                                        {
+                                            _request.transactionData[0].sampledValue.Add(new SampledValue()
+                                            {
+                                                context = ReadingContext.Transaction_End,
+                                                format = ValueFormat.Raw,
+                                                location = Location.Outlet,
+                                                phase = _request.transactionData[0].sampledValue.Where(x => x.context.HasValue).Select(x => x.phase).FirstOrDefault(),
+                                                unit = UnitOfMeasure.Wh,
+                                                measurand = Measurand.TotalEnergy,
+                                                value = decimal.Subtract(transaction.MeterStop, transaction.MeterStart).ToString()
+                                            });
+                                        }
+
+
+                                        await db.SaveChangesAsync();
+
+
+                                        if (session.IsBilling)
+                                        {
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.DataTransfer.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                           new DataTransferRequest()
+                                                           {
+                                                               messageId = "ID_TxEnergy",
+                                                               vendorId = "Phihong Technology",
+                                                               data = JsonConvert.SerializeObject(new { txId = _request.transactionId, ConnectorId = transaction.ConnectorId })
+                                                           },
+                                                           new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            });
+
+                                            db.SaveChanges();
+                                        }
+
+                                        result.Message = confirm;
+                                        result.Success = true;
+                                    }
+                                    else
+                                    {
+
+                                        result.Exception = new Exception("Can't find transactionId " + _request.transactionId);
+
+                                    }
+                                }
+
+                                #region Save MeterValue
+
+                                if (_request.transactionData != null)
+                                {
+                                    if (_request.transactionData.Count > 0)
+                                    {
+                                        using (var _meterDb = new MeterValueDBContext())
+                                        {
+                                            foreach (var item in _request.transactionData)
+                                            {
+                                                foreach (var sampleVaule in item.sampledValue)
+                                                {
+                                                    decimal value = Convert.ToDecimal(sampleVaule.value);
+
+
+                                                    string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," +
+                                 "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId";
+
+                                                    List<SqlParameter> parameter = new List<SqlParameter>
+                                        {
+                                              new SqlParameter("ChargeBoxId",session.ChargeBoxId),
+                                              new SqlParameter("ConnectorId",  (byte)_ConnectorId),
+                                              new SqlParameter("Value",value),
+                                              new SqlParameter("CreatedOn",item.timestamp),
+                                              new SqlParameter("ContextId",sampleVaule.context.HasValue ? (int)sampleVaule.context : 0),
+                                              new SqlParameter("FormatId",sampleVaule.format.HasValue ? (int)sampleVaule.format : 0),
+                                              new SqlParameter("MeasurandId",sampleVaule.measurand.HasValue ? (int)sampleVaule.measurand : 0),
+                                              new SqlParameter("PhaseId",sampleVaule.phase.HasValue ? (int)sampleVaule.phase : 0),
+                                              new SqlParameter("LocationId",sampleVaule.location.HasValue ? (int)sampleVaule.location : 0),
+                                              new SqlParameter("UnitId",sampleVaule.unit.HasValue ? (int)sampleVaule.unit : 0),
+                                              new SqlParameter("TransactionId",_request.transactionId),
+                                          };
+
+
+                                                    _meterDb.Database.ExecuteSqlCommand(sp, parameter.ToArray());
+                                                }
+                                            }
+                                        }
+
+
+                                    }
+                                }
+
+                                #endregion
+                            }
+                            catch (Exception ex)
+                            {
+                                result.Exception = new Exception("TransactionId " + _request.transactionId + " " + ex.Message);
+                                result.CallErrorMsg = "Reject Response Message";
+                                result.Success = false;
+                                // return result;
+                            }
+                        }
+                        break;
+                    case Actions.Authorize:
+                        {
+                            AuthorizeRequest _request = request as AuthorizeRequest;
+
+                            var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+                            var confirm = new AuthorizeConfirmation()
+                            {
+                                idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted }
+                            };
+                            if (_request.idTag != "Backend")
+                            {
+                                var authorization_result = await businessService.Authorize(session.ChargeBoxId, _request.idTag);
+                                confirm.idTagInfo = authorization_result.IdTagInfo;
+
+                                if (confirm.idTagInfo.status == AuthorizationStatus.Accepted && authorization_result.ChargePointFee != null)
+                                {
+                                    var price = authorization_result.ChargePointFee.Where(x => x.IsAC == session.IsAC).First();
+                                    if (price != null)
+                                    {
+
+                                        if (session.UserPrices.ContainsKey(_request.idTag))
+                                        {
+                                            session.UserPrices[_request.idTag] = price.PerkWhFee.HasValue ? JsonConvert.SerializeObject(new List<ChargingPrice>() { new ChargingPrice() { StartTime = "00:00", EndTime = "23:59", Fee = price.PerkWhFee.Value } }) : price.PerHourFee.Value.ToString();
+                                            session.UserPrices[_request.idTag] += "|+" + authorization_result.AccountBalance + "+" + "&" + price.ParkingFee + "&|" + price.Currency;
+
+                                        }
+                                        else
+                                        {
+                                            session.UserPrices.Add(_request.idTag, price.PerkWhFee.HasValue ? JsonConvert.SerializeObject(new List<ChargingPrice>() { new ChargingPrice() { StartTime = "00:00", EndTime = "23:59", Fee = price.PerkWhFee.Value } }) : price.PerHourFee.Value.ToString());
+                                            session.UserPrices[_request.idTag] += "|+" + authorization_result.AccountBalance + "+" + "&" + price.ParkingFee + "&|" + price.Currency;
+
+                                        }
+
+                                        if (session.UserDisplayPrices.ContainsKey(_request.idTag))
+                                        {
+                                            session.UserDisplayPrices[_request.idTag] = price.DisplayMessage;
+                                        }
+                                        else
+                                        {
+                                            session.UserDisplayPrices.Add(_request.idTag, price.DisplayMessage);
+                                        }
+                                    }
+                                }
+
+                            }
+                            //特例****飛宏客戶旗下的電樁,若遇到Portal沒回應的狀況 ~允許充電
+                            if (session.CustomerId.ToString().ToUpper() == "8456AED9-6DD9-4BF3-A94C-9F5DCB9506F7" && confirm.idTagInfo.status == AuthorizationStatus.ConcurrentTx)
+                            {
+                                confirm.idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
+                            }
+
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    default:
+                        {
+                            Console.WriteLine(string.Format("Not Implement {0} Logic(ExecuteCoreRequest)", request.GetType().ToString().Replace("OCPPPackage.Messages.Core.", "")));
+                        }
+                        break;
+                }
+            }
+            catch (Exception ex)
+            {
+                logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action));
+                logger.Fatal(string.Format("Data {0}", request.ToString()));
+                logger.Fatal(string.Format("Error {0}", ex.ToString()));
+                result.Exception = ex;
+            }
+
+
+            if (action == Actions.Heartbeat)
+            {
+                watch.Stop();
+                if (watch.ElapsedMilliseconds / 1000 > 3)
+                {
+                    logger.Error("Processing Hearbeat costs " + watch.ElapsedMilliseconds / 1000 + " seconds");
+                }
+            }
+            return result;
+        }
+
+        async internal Task<MessageResult> ExecuteCoreConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            try
+            {
+                switch (action)
+                {
+
+                    case Actions.DataTransfer:
+                        {
+                            DataTransferConfirmation _confirm = confirm as DataTransferConfirmation;
+                            DataTransferRequest _request = _confirm.GetRequest() as DataTransferRequest;
+                            using (var db = new MainDBContext())
+                            {
+                                var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                                x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                                if (operation != null)
+                                {
+                                    operation.FinishedOn = DateTime.UtcNow;
+                                    operation.Status = 1;//電樁有回覆
+                                    operation.EVSE_Status = (int)_confirm.status;
+                                    operation.EVSE_Value = string.IsNullOrEmpty(_confirm.data) ? "" : _confirm.data;
+                                    await db.SaveChangesAsync();
+                                }
+
+                                if (_request.messageId == "ID_FirmwareVersion")
+                                {
+                                    var machine = new Machine() { Id = session.MachineId };
+                                    if (machine != null)
+                                    {
+                                        db.Configuration.AutoDetectChangesEnabled = false;
+                                        db.Configuration.ValidateOnSaveEnabled = false;
+                                        db.Machine.Attach(machine);
+                                        machine.BoardVersions = _confirm.data;
+                                        db.Entry(machine).Property(x => x.BoardVersions).IsModified = true;
+                                        await db.SaveChangesAsync();
+                                    }
+                                }
+
+                                if (_request.messageId == "ID_TxEnergy") //計費
+                                {
+                                    if (_confirm.status == DataTransferStatus.Accepted)
+                                    {
+                                        decimal couponPoint = 0m;
+                                        string farewellMessage = string.Empty;
+                                        string receipt = string.Empty;
+                                        List<ChargingBill> bill = new List<ChargingBill>();
+                                        List<ChargingPrice> chargingPrices = new List<ChargingPrice>();
+                                        var txEnergy = JsonConvert.DeserializeObject<TransactionEnergy>(_confirm.data);
+                                        var feedto = db.TransactionRecord.Where(x => x.Id == txEnergy.TxId).Select(x => new { Id = x.Id, ConnectorId = x.ConnectorId, Fee = x.Fee, StopTime = x.StopTime, StartTime = x.StartTime }).FirstOrDefault();
+                                        decimal chargedEnergy = 0m;
+                                        if (feedto == null || string.IsNullOrEmpty(feedto.Fee)) return result;
+                                        string currency = feedto.Fee.Substring(feedto.Fee.Length - 3);
+                                        decimal chargingCost = 0;
+                                        if (feedto.Fee.Length > 58)
+                                        {
+                                            chargingPrices = JsonConvert.DeserializeObject<List<ChargingPrice>>(feedto.Fee.Split('|')[0]);
+                                            foreach (var item in txEnergy.PeriodEnergy)
+                                            {
+                                                DateTime dt = new DateTime(2021, 01, 01, int.Parse(item.Key), 0, 0, DateTimeKind.Utc);
+                                                string startTime = dt.ToString("hh:mm tt", new CultureInfo("en-us"));
+                                                decimal perfee = 0;
+
+                                                //小數點無條件捨去到第4位
+                                                var periodEnergy = (decimal)((int)Decimal.Multiply(item.Value, 10000) / (double)10000);
+                                                chargedEnergy += periodEnergy;
+                                                if (chargingPrices.Count == 1)
+                                                {
+                                                    perfee = Decimal.Multiply(periodEnergy, chargingPrices[0].Fee);
+                                                    if (bill.Count == 0)
+                                                    {
+                                                        bill.Add(new ChargingBill()
+                                                        {
+                                                            StartTime = "12:00 AM",
+                                                            EndTime = "11:59 PM",
+                                                            Fee = chargingPrices[0].Fee
+                                                        });
+                                                    }
+
+                                                    bill[0].PeriodEnergy += periodEnergy;
+
+                                                }
+                                                else
+                                                {
+                                                    var price = chargingPrices.Where(x => x.StartTime == startTime).FirstOrDefault();
+                                                    perfee = Decimal.Multiply(periodEnergy, price.Fee);
+
+                                                    bill.Add(new ChargingBill()
+                                                    {
+                                                        StartTime = price.StartTime,
+                                                        EndTime = price.EndTime,
+                                                        PeriodEnergy = periodEnergy,
+                                                        Fee = price.Fee,
+
+                                                    });
+                                                }
+                                                if (bill.Count > 0)
+                                                {
+                                                    bill[bill.Count - 1].Total += DollarRounding(perfee, session.Currency);
+                                                    chargingCost += bill[bill.Count - 1].Total;
+
+                                                    if (bill.Count == 1)
+                                                    {
+
+                                                        bill[bill.Count - 1].Total = DollarRounding(Decimal.Multiply(bill[0].PeriodEnergy, bill[0].Fee), session.Currency);
+                                                        chargingCost = bill[bill.Count - 1].Total;
+                                                    }
+                                                }
+                                            }
+                                        }
+                                        else
+                                        {
+                                            //以小時計費
+                                            foreach (var item in txEnergy.PeriodEnergy)
+                                            {  //小數點無條件捨去到第4位
+                                                var periodEnergy = (decimal)((int)Decimal.Multiply(item.Value, 10000) / (double)10000);
+                                                chargedEnergy += periodEnergy;
+                                            }
+
+                                            var fee = decimal.Parse(feedto.Fee.Split('|')[0]);
+                                            var charging_stoptime = feedto.StopTime == GlobalConfig.DefaultNullTime ? DateTime.Parse(DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm")) : DateTime.Parse(feedto.StopTime.ToString("yyyy/MM/dd HH:mm"));
+                                            var charging_starttime = DateTime.Parse(feedto.StartTime.ToString("yyyy/MM/dd HH:mm"));
+                                            chargingCost = Decimal.Multiply((decimal)charging_stoptime.Subtract(charging_starttime).TotalHours, fee);
+                                            chargingCost = DollarRounding(chargingCost, session.Currency);
+                                        }
+
+                                        // 計算停車費
+                                        var parkingFee = decimal.Parse(feedto.Fee.Split('&')[1]);
+                                        var stoptime = feedto.StopTime == GlobalConfig.DefaultNullTime ? DateTime.Parse(DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm")) : DateTime.Parse(feedto.StopTime.ToString("yyyy/MM/dd HH:mm"));
+                                        var starttime = DateTime.Parse(feedto.StartTime.ToString("yyyy/MM/dd HH:mm"));
+                                        var totalHours = stoptime.Subtract(starttime).TotalHours;
+                                        var parkingCost = Decimal.Multiply((decimal)totalHours, parkingFee);
+                                        parkingCost = DollarRounding(parkingCost, session.Currency);
+
+                                        if (feedto.StopTime != GlobalConfig.DefaultNullTime)
+                                        {
+                                            var customerInfo = db.Customer.Where(x => x.Id == session.CustomerId).Select(x => new { x.InstantStopTxReport, x.ApiUrl, x.ApiKey }).FirstOrDefault();
+
+                                            decimal accountBalance = 0;
+                                            decimal.TryParse(feedto.Fee.Split('+')[1], out accountBalance);
+
+                                            var tx = db.TransactionRecord.Where(x => x.Id == txEnergy.TxId).FirstOrDefault();
+                                            if (tx == null)
+                                            {
+                                                Console.WriteLine("Tx is empty");
+                                                return result;
+                                            }
+
+                                            if (tx.BillingDone) return result;
+
+
+                                            var startTime = new DateTime(tx.StartTime.Year, tx.StartTime.Month, tx.StartTime.Day, tx.StartTime.Hour, 0, 0);
+                                            List<ChargingBill> confirmbill = new List<ChargingBill>();
+                                            receipt = string.Format("({0} )Energy:", chargedEnergy);
+
+                                            while (startTime < tx.StopTime)
+                                            {
+                                                if (bill.Count == 1)
+                                                {
+                                                    confirmbill = bill;
+                                                    receipt += string.Format("| {0} - {1}:| {2} kWh @ ${3}/kWh=${4}", tx.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")), tx.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")),
+                                                        confirmbill[0].PeriodEnergy.ToString("0.0000"), bill[0].Fee, bill[0].Total);
+
+                                                    break;
+                                                }
+                                                if (bill.Count == 0)
+                                                {
+                                                    receipt += string.Format("| {0} - {1} @ ${2}/hr=${3}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")),
+                                                       feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), feedto.Fee.Split('|')[0], chargingCost);
+
+                                                    break;
+                                                }
+                                                if (bill.Count > 1)
+                                                {
+                                                    var time = startTime.ToString("hh:mm tt", new CultureInfo("en-us"));
+                                                    var tt = bill.Where(x => x.StartTime == time).FirstOrDefault();
+                                                    confirmbill.Add(tt);
+                                                    if (confirmbill.Count == 1)
+                                                    {
+                                                        confirmbill[0].StartTime = tx.StartTime.ToString("hh:mm tt", new CultureInfo("en-us"));
+                                                    }
+
+
+                                                    var stopTimeText = tx.StopTime.ToString("hh:mm tt", new CultureInfo("en-us"));
+                                                    if (confirmbill[confirmbill.Count - 1].StartTime.Contains(stopTimeText.Split(' ')[1]))
+                                                    {
+                                                        var subHourText = (int.Parse(stopTimeText.Split(':')[0])).ToString();
+                                                        subHourText = subHourText.Length == 1 ? "0" + subHourText : subHourText;
+                                                        if (confirmbill[confirmbill.Count - 1].StartTime.Contains(subHourText))
+                                                        {
+                                                            confirmbill[confirmbill.Count - 1].EndTime = stopTimeText;
+                                                        }
+
+                                                    }
+                                                    receipt += string.Format("| {0} - {1}:| {2} kWh @ ${3}/kWh=${4}", confirmbill[confirmbill.Count - 1].StartTime, confirmbill[confirmbill.Count - 1].EndTime,
+                                                        confirmbill[confirmbill.Count - 1].PeriodEnergy.ToString("0.0000"), confirmbill[confirmbill.Count - 1].Fee, confirmbill[confirmbill.Count - 1].Total);
+
+                                                    if (confirmbill.Count == 24) break;
+
+                                                }
+                                                startTime = startTime.AddHours(1);
+
+                                            }
+
+                                            if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
+                                            {
+                                                chargingCost = confirmbill.Count > 0 ? confirmbill.Sum(x => x.Total) : chargingCost;
+                                                chargingCost = chargedEnergy == 0 ? 0 : (chargingCost + parkingCost < 1 ? 1 : chargingCost);  //台泥最低一元
+                                                receipt += string.Format("|Total Energy Fee : ${0}", chargingCost);
+
+                                                receipt += string.Format("|Parking Fee: | {0} - {1} @ ${2}/hr=${3}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")),
+                                                feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), parkingFee, parkingCost);
+                                                tx.Cost = chargingCost + parkingCost;
+                                            }
+                                            else
+                                            {
+                                                chargingCost = confirmbill.Count > 0 ? confirmbill.Sum(x => x.Total) : chargingCost;
+                                                receipt += string.Format("|Total Energy Fee : ${0}", chargingCost);
+
+                                                receipt += string.Format("|Parking Fee: | {0} - {1} @ ${2}/hr=${3}", feedto.StartTime.ToString("hh:mm tt", new CultureInfo("en-us")),
+                                                feedto.StopTime.ToString("hh:mm tt", new CultureInfo("en-us")), parkingFee, parkingCost);
+                                                tx.Cost = chargingCost + parkingCost;
+                                            }
+
+
+                                            if (customerInfo != null && customerInfo.InstantStopTxReport)
+                                            {
+
+                                                var request = new
+                                                {
+                                                    ChargeBoxId = tx.ChargeBoxId,
+                                                    ConnectorId = tx.ConnectorId,
+                                                    SessionId = tx.Id,
+                                                    MeterStart = tx.MeterStart,
+                                                    MeterStop = tx.MeterStop,
+                                                    IdTag = tx.StartIdTag,
+                                                    StartTime = tx.StartTime.ToString(GlobalConfig.UTC_DATETIMEFORMAT),
+                                                    StopTime = tx.StopTime.ToString(GlobalConfig.UTC_DATETIMEFORMAT),
+                                                    StopReason = tx.StopReasonId < 1 ? "Unknown" : (tx.StopReasonId > 12 ? "Unknown" : ((Reason)tx.StopReasonId).ToString()),
+                                                    Receipt = tx.Receipt,
+                                                    TotalCost = tx.Cost,
+                                                    Fee = tx.Fee
+
+                                                };
+
+                                                logger.Debug("completed_session " + JsonConvert.SerializeObject(request));
+                                                var response = await httpClient.Post(customerInfo.ApiUrl + "completed_session", new Dictionary<string, string>()
+                                                {
+                                                    { "PartnerId",session.CustomerId.ToString()}
+
+                                                }, request, customerInfo.ApiKey);
+
+                                                var _httpResult = JsonConvert.DeserializeObject<CPOOuterResponse>(response.Response);
+                                                logger.Debug("completed_session Response" + response.Response);
+                                                JObject jo = JObject.Parse(_httpResult.Data);
+                                                if (jo.ContainsKey("CouponPoint"))
+                                                {
+                                                    couponPoint = jo["CouponPoint"].Value<Decimal>();
+
+                                                }
+
+                                                if (jo.ContainsKey("FarewellMessage"))
+                                                {
+                                                    farewellMessage = jo["FarewellMessage"].Value<string>();
+                                                }
+                                            }
+
+                                            tx.Receipt = receipt;
+                                            tx.BillingDone = true;
+                                            db.Configuration.AutoDetectChangesEnabled = false;
+                                            db.Configuration.ValidateOnSaveEnabled = false;
+                                            db.TransactionRecord.Attach(tx);
+                                            db.Entry(tx).Property(x => x.Cost).IsModified = true;
+                                            db.Entry(tx).Property(x => x.Receipt).IsModified = true;
+                                            db.Entry(tx).Property(x => x.BillingDone).IsModified = true;
+
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.DataTransfer.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                            new DataTransferRequest()
+                                                            {
+                                                                messageId = "FinalCost",
+                                                                vendorId = "Phihong Technology",
+                                                                data = JsonConvert.SerializeObject(new
+                                                                {
+                                                                    txId = txEnergy.TxId,
+                                                                    description = JsonConvert.SerializeObject(new
+                                                                    {
+                                                                        chargedEnergy = chargedEnergy,
+                                                                        chargingFee = chargingCost,
+                                                                        parkTime = (int)stoptime.Subtract(starttime).TotalSeconds,
+                                                                        parkingFee = parkingCost,
+                                                                        currency = currency,
+                                                                        couponPoint = couponPoint,
+                                                                        accountBalance = accountBalance - tx.Cost,
+                                                                        farewellMessage = farewellMessage
+                                                                    })
+                                                                })
+
+                                                            },
+                                                            new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            }); ;
+
+                                            await db.SaveChangesAsync();
+
+                                            using (var meterdb = new MeterValueDBContext())
+                                            {
+                                                string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," +
+                                   "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId";
+
+                                                List<SqlParameter> parameter = new List<SqlParameter>
+                                                {
+                                                      new SqlParameter("ChargeBoxId",session.ChargeBoxId),
+                                                      new SqlParameter("ConnectorId",  (byte)feedto.ConnectorId),
+                                                      new SqlParameter("Value",chargingCost),
+                                                      new SqlParameter("CreatedOn",DateTime.UtcNow),
+                                                      new SqlParameter("ContextId",(int)ReadingContext.Sample_Periodic),
+                                                      new SqlParameter("FormatId",(int)ValueFormat.Raw),
+                                                      new SqlParameter("MeasurandId",(int)Measurand.TotalCost),
+                                                      new SqlParameter("PhaseId", -1),
+                                                      new SqlParameter("LocationId", -1),
+                                                      new SqlParameter("UnitId", -1),
+                                                      new SqlParameter("TransactionId",feedto.Id),
+                                                };
+
+
+                                                meterdb.Database.ExecuteSqlCommand(sp, parameter.ToArray());
+                                            }
+
+                                            using (SqlConnection conn = new SqlConnection(webConnectionString))
+                                            {
+                                                var parameters = new DynamicParameters();
+                                                parameters.Add("@IdTag", tx.StartIdTag, DbType.String, ParameterDirection.Input);
+                                                parameters.Add("@parentIdTag", accountBalance - tx.Cost, DbType.String, ParameterDirection.Input);
+                                                string strSql = "update [dbo].[LocalListDetail] set parentIdTag =@parentIdTag  where ListId = 27 and IdTag=@IdTag; ";
+                                                await conn.ExecuteAsync(strSql, parameters);
+
+                                            }
+
+                                            #region 提供給PHA 過CDFA認證 使用
+                                            if (tx.CustomerId == Guid.Parse("10C7F5BD-C89A-4E2A-8611-B617E0B41A73"))
+                                            {
+                                                var mail_response = new OuterHttpClient().PostFormDataAsync("http://ocpp.phihong.com.tw/CDFA/" + tx.Id, new Dictionary<string, string>()
+                                                {
+                                                    { "email","2"},
+                                                    { "to","wonderj@phihongusa.com;jessica_tseng@phihong.com.tw"}
+                                                    //{ "to","jessica_tseng@phihong.com.tw"}
+                                               }, null);
+
+                                                Console.WriteLine(JsonConvert.SerializeObject(mail_response));
+
+                                            }
+                                            #endregion
+
+                                        }
+                                        else
+                                        {
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.DataTransfer.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                 new DataTransferRequest()
+                                                 {
+                                                     messageId = "RunningCost",
+                                                     vendorId = "Phihong Technology",
+                                                     data = JsonConvert.SerializeObject(new
+                                                     {
+                                                         txId = txEnergy.TxId,
+                                                         description = JsonConvert.SerializeObject(new
+                                                         {
+                                                             chargedEnergy = chargedEnergy,
+                                                             chargingFee = chargingCost,
+                                                             parkTime = (int)stoptime.Subtract(starttime).TotalSeconds,
+                                                             parkingFee = parkingCost,
+                                                             currency = currency
+                                                         })
+
+                                                     })
+
+                                                 },
+                                                 new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            }); ;
+
+                                            await db.SaveChangesAsync();
+
+                                            using (var meterdb = new MeterValueDBContext())
+                                            {
+                                                string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," +
+                       "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId";
+
+                                                List<SqlParameter> parameter = new List<SqlParameter>
+                                                {
+                                                      new SqlParameter("ChargeBoxId",session.ChargeBoxId),
+                                                      new SqlParameter("ConnectorId",  (byte)feedto.ConnectorId),
+                                                      new SqlParameter("Value",chargingCost),
+                                                      new SqlParameter("CreatedOn",DateTime.UtcNow),
+                                                      new SqlParameter("ContextId",(int)ReadingContext.Sample_Periodic),
+                                                      new SqlParameter("FormatId",(int)ValueFormat.Raw),
+                                                      new SqlParameter("MeasurandId",(int)Measurand.ChargingCost),
+                                                      new SqlParameter("PhaseId", -1),
+                                                      new SqlParameter("LocationId", -1),
+                                                      new SqlParameter("UnitId", -1),
+                                                      new SqlParameter("TransactionId",feedto.Id),
+                                                };
+
+
+                                                meterdb.Database.ExecuteSqlCommand(sp, parameter.ToArray());
+                                            }
+
+                                        }
+
+
+                                    }
+
+                                }
+
+                                #region 台泥
+                                if (_request.messageId == "ID_GetTxUserInfo")
+                                {
+                                    var txUserInfo = JsonConvert.DeserializeObject<ID_GetTxUserInfo>(_confirm.data);
+                                    if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
+                                    {
+                                        var request = new
+                                        {
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            ConnectorId = txUserInfo.ConnectorId,
+                                            SessionId = txUserInfo.TxId,
+                                            SerialNo = txUserInfo.SerialNo,
+                                            StartTime = txUserInfo.StartTime.ToString(GlobalConfig.UTC_DATETIMEFORMAT),
+                                            VEMData = txUserInfo.VEMData
+                                        };
+
+                                        var response = httpClient.Post(GlobalConfig.TCC_API_URL + "start_session", new Dictionary<string, string>()
+                                        {
+                                            { "PartnerId",session.CustomerId.ToString()}
+
+                                        }, request, GlobalConfig.TCC_SALTKEY);
+
+                                        logger.Debug(JsonConvert.SerializeObject(response));
+                                    }
+
+                                }
+
+                                #endregion
+                            }
+                        }
+                        break;
+                    case Actions.ChangeAvailability:
+                        {
+                            ChangeAvailabilityConfirmation _confirm = confirm as ChangeAvailabilityConfirmation;
+                            ChangeAvailabilityRequest _request = _confirm.GetRequest() as ChangeAvailabilityRequest;
+
+                            using (var db = new MainDBContext())
+                            {
+                                var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                                x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                                if (operation != null)
+                                {
+                                    operation.FinishedOn = DateTime.UtcNow;
+                                    operation.Status = 1;//電樁有回覆
+                                    operation.EVSE_Status = (int)_confirm.status;
+                                    operation.EVSE_Value = _confirm.status.ToString();
+                                    await db.SaveChangesAsync();
+                                }
+
+                            }
+                        }
+                        break;
+
+                    case Actions.ClearCache:
+                        {
+                            ClearCacheConfirmation _confirm = confirm as ClearCacheConfirmation;
+                            ClearCacheRequest _request = _confirm.GetRequest() as ClearCacheRequest;
+
+                            using (var db = new MainDBContext())
+                            {
+                                var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                                x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                                if (operation != null)
+                                {
+                                    operation.FinishedOn = DateTime.UtcNow;
+                                    operation.Status = 1;//電樁有回覆
+                                    operation.EVSE_Status = (int)_confirm.status;
+                                    operation.EVSE_Value = _confirm.status.ToString();
+                                    await db.SaveChangesAsync();
+                                }
+
+                            }
+                        }
+                        break;
+                    case Actions.RemoteStartTransaction:
+                        {
+                            RemoteStartTransactionConfirmation _confirm = confirm as RemoteStartTransactionConfirmation;
+                            RemoteStartTransactionRequest _request = _confirm.GetRequest() as RemoteStartTransactionRequest;
+
+                            using (var db = new MainDBContext())
+                            {
+                                var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                                x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                                if (operation != null)
+                                {
+                                    operation.FinishedOn = DateTime.UtcNow;
+                                    operation.Status = 1;//電樁有回覆
+                                    operation.EVSE_Status = (int)_confirm.status;
+                                    operation.EVSE_Value = _confirm.status.ToString();
+                                    await db.SaveChangesAsync();
+                                }
+
+                            }
+                        }
+                        break;
+                    case Actions.RemoteStopTransaction:
+                        {
+                            RemoteStopTransactionConfirmation _confirm = confirm as RemoteStopTransactionConfirmation;
+                            RemoteStopTransactionRequest _request = _confirm.GetRequest() as RemoteStopTransactionRequest;
+
+                            using (var db = new MainDBContext())
+                            {
+                                var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                                x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                                if (operation != null)
+                                {
+                                    operation.FinishedOn = DateTime.UtcNow;
+                                    operation.Status = 1;//電樁有回覆
+                                    operation.EVSE_Status = (int)_confirm.status;
+                                    operation.EVSE_Value = _confirm.status.ToString();
+                                    await db.SaveChangesAsync();
+                                }
+
+                            }
+                        }
+                        break;
+                    case Actions.Reset:
+                        {
+                            ResetConfirmation _confirm = confirm as ResetConfirmation;
+                            ResetRequest _request = _confirm.GetRequest() as ResetRequest;
+
+                            using (var db = new MainDBContext())
+                            {
+                                var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                                x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                                if (operation != null)
+                                {
+                                    operation.FinishedOn = DateTime.UtcNow;
+                                    operation.Status = 1;//電樁有回覆
+                                    operation.EVSE_Status = (int)_confirm.status;
+                                    operation.EVSE_Value = _confirm.status.ToString();
+                                    await db.SaveChangesAsync();
+                                }
+
+                            }
+                        }
+                        break;
+                    case Actions.ChangeConfiguration:
+                        {
+                            ChangeConfigurationConfirmation _confirm = confirm as ChangeConfigurationConfirmation;
+                            ChangeConfigurationRequest _request = _confirm.GetRequest() as ChangeConfigurationRequest;
+
+                            using (var db = new MainDBContext())
+                            {
+                                var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                         x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+
+                                if (operation != null)
+                                {
+                                    operation.FinishedOn = DateTime.UtcNow;
+                                    operation.Status = 1;//電樁有回覆
+                                    operation.EVSE_Status = (int)_confirm.status;
+                                    operation.EVSE_Value = _confirm.status.ToString();
+
+                                }
+
+                                if (_confirm.status == Packet.Messages.SubTypes.ConfigurationStatus.Accepted || _confirm.status == Packet.Messages.SubTypes.ConfigurationStatus.RebootRequired)
+                                {
+                                    var configure = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList();
+
+                                    var foundConfig = configure.Find(x => x.ConfigureName == _request.key);
+                                    if (foundConfig != null)
+                                    {
+                                        foundConfig.ReadOnly = false;
+                                        foundConfig.ConfigureSetting = _request.value;
+                                    }
+                                    else
+                                    {
+                                        db.MachineConfiguration.Add(new MachineConfiguration()
+                                        {
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            ConfigureName = _request.key,
+                                            ReadOnly = false,
+                                            ConfigureSetting = _request.value
+                                        });
+                                    }
+                                }
+                                await db.SaveChangesAsync();
+                            }
+
+                        }
+                        break;
+                    case Actions.GetConfiguration:
+                        {
+
+                            try
+                            {
+                                GetConfigurationConfirmation _confirm = confirm as GetConfigurationConfirmation;
+                                //  GetConfigurationRequest _request = _confirm.GetRequest() as GetConfigurationRequest;
+
+                                using (var db = new MainDBContext())
+                                {
+                                    var configure = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList();
+
+                                    if (_confirm.configurationKey != null)
+                                    {
+                                        foreach (var item in _confirm.configurationKey)
+                                        {
+                                            string oldValue = string.Empty;
+                                            if (item.key == null)
+                                            {
+                                                Console.WriteLine("*********************");
+                                            }
+                                            var foundConfig = configure.Find(x => x.ConfigureName == item.key);
+
+
+                                            if (foundConfig != null)
+                                            {
+                                                if (foundConfig.ConfigureName == null)
+                                                {
+                                                    Console.WriteLine("*********************");
+                                                }
+
+                                                if (foundConfig.ConfigureName == "SecurityProfile")
+                                                {
+                                                    oldValue = foundConfig.ConfigureSetting;
+                                                }
+
+                                                foundConfig.ReadOnly = item.IsReadOnly;
+                                                foundConfig.ConfigureSetting = string.IsNullOrEmpty(item.value) ? string.Empty : item.value;
+                                            }
+                                            else
+                                            {
+                                                db.MachineConfiguration.Add(new MachineConfiguration()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    ConfigureName = item.key,
+                                                    ReadOnly = item.IsReadOnly,
+                                                    ConfigureSetting = string.IsNullOrEmpty(item.value) ? string.Empty : item.value,
+                                                    Exists = true
+                                                });
+                                            }
+
+
+                                        }
+                                    }
+                                    if (_confirm.unknownKey != null)
+                                    {
+
+                                        foreach (var item in _confirm.unknownKey)
+                                        {
+                                            var foundConfig = configure.Find(x => x.ConfigureName == item);
+                                            if (foundConfig != null)
+                                            {
+                                                foundConfig.ReadOnly = true;
+                                                foundConfig.ConfigureSetting = string.Empty;
+                                                foundConfig.Exists = false;
+                                            }
+                                            else
+                                            {
+                                                db.MachineConfiguration.Add(new MachineConfiguration()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    ConfigureName = item
+                                                });
+                                            }
+                                        }
+                                    }
+
+                                    var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                                   x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+
+                                    if (operation != null)
+                                    {
+                                        operation.FinishedOn = DateTime.UtcNow;
+                                        operation.Status = 1;//電樁有回覆
+                                        operation.EVSE_Status = 1;
+                                        operation.EVSE_Value = JsonConvert.SerializeObject(_confirm.configurationKey, Formatting.None);
+
+                                    }
+
+                                    await db.SaveChangesAsync();
+
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                logger.Error(ex.ToString());
+                            }
+
+                        }
+                        break;
+                    case Actions.UnlockConnector:
+                        {
+                            UnlockConnectorConfirmation _confirm = confirm as UnlockConnectorConfirmation;
+                            UnlockConnectorRequest _request = _confirm.GetRequest() as UnlockConnectorRequest;
+
+                            using (var db = new MainDBContext())
+                            {
+                                var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                                x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                                if (operation != null)
+                                {
+                                    operation.FinishedOn = DateTime.UtcNow;
+                                    operation.Status = 1;//電樁有回覆
+                                    operation.EVSE_Status = (int)_confirm.status;
+                                    operation.EVSE_Value = _confirm.status.ToString();
+                                    await db.SaveChangesAsync();
+                                }
+
+                            }
+                        }
+                        break;
+                    default:
+                        {
+                            Console.WriteLine(string.Format("Not Implement {0} Logic(ExecuteCoreConfirm)", confirm.GetType().ToString().Replace("OCPPPackage.Messages.Core.", "")));
+                        }
+                        break;
+                }
+            }
+            catch (Exception ex)
+            {
+                logger.Debug("123 " + action + " " + ex.ToString());
+            }
+
+
+
+            return result;
+        }
+
+
+        internal MessageResult ReceivedCoreError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.ChangeAvailability:
+                case Actions.ChangeConfiguration:
+                case Actions.ClearCache:
+                case Actions.RemoteStartTransaction:
+                case Actions.RemoteStopTransaction:
+                case Actions.Reset:
+                case Actions.GetConfiguration:
+                case Actions.UnlockConnector:
+                case Actions.DataTransfer:
+                    {
+                        if (action == Actions.DataTransfer)
+                        {
+                            logger.Debug(string.Format("DataTransfer Error {0}: {1}", session.ChargeBoxId, requestId));
+                        }
+
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+
+                    }
+                    break;
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic(ReceivedCoreError)", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+
+
+        /// <summary>
+        /// 依據幣值處理4捨5入
+        /// </summary>
+        /// <param name="money"></param>
+        /// <param name="currency"></param>
+        /// <returns></returns>
+        private decimal DollarRounding(decimal money, string currency)
+        {
+
+
+            if (currency == "USD" || currency == "EUR")
+            {
+
+                //0.4867
+                if ((double)((int)(money * 100) + 0.5) <= (double)(money * 100))
+                {
+
+                    //money = Decimal.Add(money, (decimal)0.01);//0.4967
+
+                }
+                money = Math.Round(money, 2, MidpointRounding.AwayFromZero);
+                money = Decimal.Parse(money.ToString("0.00"));
+
+
+            }
+            else
+            {
+                if ((double)((int)(money) + 0.5) <= (double)money)
+                {
+                    //  money = (int) money + 1;
+                }
+                money = Math.Round(money, 0, MidpointRounding.AwayFromZero);
+                money = Decimal.Parse(money.ToString("0"));
+            }
+
+            return money;
+        }
+    }
+}

+ 228 - 0
EVCB_OCPP.WSServer.backup/Message/FirmwareManagementProfileHandler.cs

@@ -0,0 +1,228 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Domain.Models.Database;
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.FirmwareManagement;
+using Newtonsoft.Json;
+using OCPPServer.Protocol;
+using System;
+using System.Data.Entity;
+using System.Linq;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal partial class ProfileHandler
+    {
+        internal MessageResult ExecuteFirmwareManagementRequest(Actions action, ClientData session, IRequest request)
+        {
+            MessageResult result = new MessageResult() { Success = false };
+            try
+            {
+                switch (action)
+                {
+
+                    case Actions.FirmwareStatusNotification:
+                        {
+                            FirmwareStatusNotificationRequest _request = request as FirmwareStatusNotificationRequest;
+
+                            if (_request.status == Packet.Messages.SubTypes.FirmwareStatus.Idle)
+                            {
+                                string requestId = Guid.NewGuid().ToString();
+                                using (var db = new MainDBContext())
+                                {
+                                    var machine = db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true && x.FW_AssignedVersion.HasValue
+                                       && x.FW_AssignedVersion != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
+                                        .Select(x => new { x.Id, x.FW_AssignedVersion }).AsNoTracking().FirstOrDefault();
+
+                                    if (machine != null)
+                                    {
+                                        var mv = db.MachineVersionFile.Include(c => c.UploadFile)
+                                         .Where(c => c.Id == machine.FW_AssignedVersion.Value).First();
+
+                                        string downloadUrl = mv.UploadFile.FileUrl;
+
+                                        var _updateFWrequest = new UpdateFirmwareRequest()
+                                        {
+                                            location = new Uri(downloadUrl),
+                                            retries = 3,
+                                            retrieveDate = DateTime.UtcNow,
+                                            retryInterval = 10
+                                        };
+
+                                        db.MachineOperateRecord.Add(new MachineOperateRecord()
+                                        {
+                                            CreatedOn = DateTime.UtcNow,
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            SerialNo = requestId,
+                                            RequestContent = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                            EVSE_Status = 0,
+                                            EVSE_Value = "Fw Version:" + machine.FW_AssignedVersion,
+                                            Status = 0,
+                                            RequestType = 0,
+                                            Action = _updateFWrequest.Action.ToString()
+
+                                        });
+
+                                        db.ServerMessage.Add(new ServerMessage()
+                                        {
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            CreatedBy = "Server",
+                                            CreatedOn = DateTime.UtcNow,
+                                            OutAction = _updateFWrequest.Action.ToString(),
+                                            OutRequest = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                            SerialNo = requestId,
+                                            InMessage = string.Empty
+
+                                        });
+
+                                        db.SaveChanges();
+
+                                    }
+
+                                }
+                            }
+                            else
+                            {
+                                using (var db = new MainDBContext())
+                                {
+                                    var item = db.MachineOperateRecord.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.RequestType == 0)
+                                        .OrderByDescending(x => x.CreatedOn).FirstOrDefault();
+                                    if (item != null)
+                                    {
+                                        item.EVSE_Status = (int)_request.status;
+                                        item.FinishedOn = DateTime.UtcNow;
+                                        if (string.IsNullOrEmpty(item.EVSE_Value))
+                                        {
+                                            Console.WriteLine("怎麼悾悾的");
+                                        }
+
+                                        if (!string.IsNullOrEmpty(item.EVSE_Value) && _request.status == Packet.Messages.SubTypes.FirmwareStatus.Installed)
+                                        {
+                                            int version = 0;
+                                            int.TryParse(item.EVSE_Value.Split(':').Last(), out version);
+                                            var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+                                            machine.FW_VersionReport = version;
+                                        }
+                                    }
+
+
+
+                                    db.SaveChanges();
+                                }
+                            }
+
+                            var confirm = new FirmwareStatusNotificationConfirmation() { };
+
+                            result.Message = confirm;
+                            result.Success = true;
+                        }
+                        break;
+                    case Actions.DiagnosticsStatusNotification:
+                        {
+                            DiagnosticsStatusNotificationRequest _request = request as DiagnosticsStatusNotificationRequest;
+
+                            var confirm = new DiagnosticsStatusNotificationConfirmation() { };
+
+                            result.Message = confirm;
+                            result.Success = true;
+
+                        }
+                        break;
+
+                    default:
+                        {
+                            Console.WriteLine(string.Format("Not Implement {0} Logic", request.GetType().ToString().Replace("OCPPPackage.Messages.FirmwareManagement.", "")));
+                        }
+                        break;
+                }
+            }
+            catch (Exception ex)
+            {
+                logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action));
+                logger.Fatal(string.Format("Data {0}", request.ToString()));
+                logger.Fatal(string.Format("Error {0}", ex.ToString()));
+                result.Exception = ex;
+            }
+            return result;
+        }
+
+        internal MessageResult ExecuteFirmwareManagementConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.UpdateFirmware:
+                case Actions.GetDiagnostics:
+                    {
+                        string evse_rep = string.Empty;
+                        if (confirm is GetDiagnosticsConfirmation)
+                        {
+                            var confirmation = confirm as GetDiagnosticsConfirmation;
+                            evse_rep = confirmation.fileName;
+                        }
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)1;//OK
+                                operation.EVSE_Value = string.IsNullOrEmpty(evse_rep) ? operation.EVSE_Value : evse_rep;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.FirmwareManagement.", "")));
+                    }
+                    break;
+            }
+            return result;
+        }
+
+
+        internal MessageResult ReceivedFirmwareManagementError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.FirmwareStatusNotification:
+                case Actions.UpdateFirmware:
+                case Actions.GetDiagnostics:
+                case Actions.DiagnosticsStatusNotification:
+                    {
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+    }
+}

+ 109 - 0
EVCB_OCPP.WSServer.backup/Message/LocalAuthListManagementProfileHandler.cs

@@ -0,0 +1,109 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.LocalAuthListManagement;
+using OCPPServer.Protocol;
+using System;
+using System.Linq;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal partial class ProfileHandler
+    {
+
+
+
+
+        internal MessageResult ExecuteLocalAuthListManagementConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.GetLocalListVersion:
+                    {
+                        GetLocalListVersionConfirmation _confirm = confirm as GetLocalListVersionConfirmation;
+                        GetLocalListVersionRequest _request = _confirm.GetRequest() as GetLocalListVersionRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = 1;//OK
+                                operation.EVSE_Value = _confirm.listVersion.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                case Actions.SendLocalList:
+                    {
+                        SendLocalListConfirmation _confirm = confirm as SendLocalListConfirmation;
+                        SendLocalListRequest _request = _confirm.GetRequest() as SendLocalListRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK     
+                                operation.EVSE_Value = _confirm.status.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.RemoteTrigger.", "")));
+                    }
+                    break;
+            }
+            return result;
+        }
+
+
+        internal MessageResult ReceivedLocalAuthListManagementError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.SendLocalList:
+                case Actions.GetLocalListVersion:
+                    {
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+    }
+}

+ 54 - 0
EVCB_OCPP.WSServer.backup/Message/MessageResult.cs

@@ -0,0 +1,54 @@
+using EVCB_OCPP.Packet.Messages;
+using System;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal class MessageResult
+    {
+
+        internal MessageResult()
+        {
+            Success = true;
+        }
+
+        internal string RequestId { set; get; }
+
+        internal string UUID { get; set; }
+
+        internal string Action { get; set; }
+
+        internal int Id { get; set; }
+
+        internal bool Success { get; set; }
+
+        internal object Message { get; set; }
+
+        internal Exception Exception { get; set; }
+
+        internal string CallErrorMsg { get; set; }
+
+        internal string ReceivedErrorCode { get; set; }
+
+
+
+
+
+
+
+    }
+
+
+    internal class BasicMessageResult
+    {
+        internal IRequest Request { set; get; }
+
+        internal IConfirmation Confirmation { set; get; }
+
+        internal EVCB_OCPP20.Packet.Messages.IRequest Request20 { set; get; }
+
+        internal EVCB_OCPP20.Packet.Messages.IConfirmation Confirmation20 { set; get; }
+
+        internal Exception Exception { get; set; }
+    }
+
+}

+ 50 - 0
EVCB_OCPP.WSServer.backup/Message/NeedConfirmMessage.cs

@@ -0,0 +1,50 @@
+using System;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    public class NeedConfirmMessage
+    {
+        /// <summary>
+        /// 資料庫的ID
+        /// </summary>
+        public int Id { get; set; }
+
+        public string ChargePointSerialNumber { get; set; }
+
+        /// <summary>
+        /// 傳送次數
+        /// </summary>
+        public int SentTimes { get; set; }
+
+        /// <summary>
+        /// 傳送間隔秒數
+        /// </summary>
+        public int SentInterval { get; set; }
+
+
+        /// <summary>
+        /// 送出訊息
+        /// </summary>
+        public string SentMessage { get; set; }
+
+        /// <summary>
+        /// 送出的UUID
+        /// </summary>
+        public string SentUniqueId { get; set; }
+
+        ///// <summary>
+        ///// 送出的action
+        ///// </summary>
+        public string SentAction { get; set; }
+
+        public DateTime SentOn { set; get; }
+
+        /// <summary>
+        /// 請求 Id
+        /// </summary>
+        public string RequestId { set; get; }
+
+        public string CreatedBy { set; get; }
+
+    }
+}

+ 347 - 0
EVCB_OCPP.WSServer.backup/Message/OCPP16MessageHandler.cs

@@ -0,0 +1,347 @@
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.Basic;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using NLog;
+using OCPPServer.Protocol;
+using System;
+using System.Collections.Generic;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    /// <summary>
+    /// 實現 OCPP16 基本傳送規範,
+    /// 1.訊息 基本格式,將訊息包裝成 Call 、CallResult、CallError 三種格式
+    /// 2.OCPP 定義的傳送規則:交易相關的訊息必須依照時序性傳送,一個傳完才能接著送下一個(忽略規則 由Center System定義)
+    /// </summary>
+    internal class OCPP16MessageHandler
+    {
+        static protected ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+
+        #region 傳送 or 解析訊息需要欄位
+        private const int INDEX_MESSAGEID = 0;
+        private const int INDEX_UNIQUEID = 1;
+        internal const int TYPENUMBER_CALL = 2;
+        private const int INDEX_CALL_ACTION = 2;
+        private const int INDEX_CALL_PAYLOAD = 3;
+
+        internal const int TYPENUMBER_CALLRESULT = 3;
+        private const int INDEX_CALLRESULT_PAYLOAD = 2;
+
+        internal const int TYPENUMBER_CALLERROR = 4;
+        private const int INDEX_CALLERROR_ERRORCODE = 2;
+        private const int INDEX_CALLERROR_DESCRIPTION = 3;
+        private const int INDEX_CALLERROR_PAYLOAD = 4;
+
+        private const string CALL_FORMAT = "[2,\"{0}\",\"{1}\",{2}]";
+        private const string CALLRESULT_FORMAT = "[3,\"{0}\",{1}]";
+        private const string CALLERROR_FORMAT = "[4,\"{0}\",\"{1}\",\"{2}\",{3}]";
+        private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+        private const string DATE_FORMAT_WITH_MS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+        #endregion
+
+        private List<Profile> profiles = new List<Profile>()
+        {
+             new CoreProfile(),
+             new FirmwareManagementProfile(),
+             new ReservationProfile(),
+             new RemoteTriggerProfile(),
+             new SmartChargingProfile(),
+             new LocalAuthListManagementProfile(),
+             new SecurityProfile()
+        };
+
+
+        /// <summary>
+        /// 將收到的封包做基本的拆解分成 Call 、CallResult、CallError
+        /// </summary>
+        /// <param name="client"></param>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        internal MessageResult AnalysisReceiveData(ClientData client, string data)
+        {
+            MessageResult result = new MessageResult();
+            try
+            {
+
+                var msg = Parse(data);
+                if (msg != null)
+                {
+
+                    result.UUID = msg.Id;
+                    switch (msg.TypeId)
+                    {
+                        case TYPENUMBER_CALL:
+                            {
+                                //只有CallMessage 才有在RawData有Action
+                                BasicMessageResult baseResult = UnPackPayloadbyCall(msg.Action, msg.Payload.ToString());
+                                Actions action = Actions.None;
+                                Enum.TryParse<Actions>(msg.Action, out action);
+                                result.Action = msg.Action;
+                                if (baseResult.Request != null)
+                                {
+                                    if (baseResult.Request.Validate())
+                                    {
+                                        result.Id = TYPENUMBER_CALL;
+                                        result.Message = baseResult.Request;
+
+                                    }
+                                    else
+                                    {
+
+                                        string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
+                                             OCPPErrorDescription.OccurenceConstraintViolation);
+                                        result.Id = TYPENUMBER_CALL;
+                                        result.Message = baseResult.Request;
+                                        result.Success = false;
+                                        result.CallErrorMsg = replyMsg;
+                                        result.Exception = new Exception("Validation Failed");
+
+                                    }
+                                }
+                                else
+                                {
+
+                                    string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation, OCPPErrorDescription.OccurenceConstraintViolation);
+                                    result.Id = TYPENUMBER_CALL;
+                                    result.Message = baseResult.Request;
+                                    result.Success = false;
+                                    result.CallErrorMsg = replyMsg;
+                                    result.Exception = baseResult.Exception;
+                                }
+
+                            }
+                            break;
+                        case TYPENUMBER_CALLRESULT:
+                            {
+                                BasicMessageResult baseResult = UnPackPayloadbyCallResult(client.queue, msg.Id, msg.Payload.ToString());
+
+                                if (baseResult.Confirmation != null)
+                                {
+
+                                    if (baseResult.Confirmation.Validate())
+                                    {
+                                        result.Id = TYPENUMBER_CALLRESULT;
+                                        result.Message = baseResult.Confirmation;
+                                        result.Action = baseResult.Confirmation.GetRequest().Action;
+                                        //return data
+                                    }
+                                    else
+                                    {
+                                        string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
+                                      OCPPErrorDescription.OccurenceConstraintViolation);
+                                        result.Id = TYPENUMBER_CALLRESULT;
+                                        result.Message = baseResult.Confirmation;
+                                        result.Success = false;
+                                        result.CallErrorMsg = replyMsg;
+                                        result.Exception = new Exception("Validate Failed");
+                                    }
+                                }
+                                else
+                                {
+                                    string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
+                                   OCPPErrorDescription.OccurenceConstraintViolation);
+                                    result.Id = TYPENUMBER_CALLRESULT;
+                                    result.Message = baseResult.Confirmation;
+                                    result.Success = false;
+                                    result.CallErrorMsg = replyMsg;
+                                    result.Exception = baseResult.Exception;
+                                }
+
+                            }
+                            break;
+                        case TYPENUMBER_CALLERROR:
+                            {
+                                result.Id = TYPENUMBER_CALLERROR;
+                                var sentRequest = UnPackPayloadbyCallError(client.queue, msg.Id);
+
+                                if (sentRequest != null)
+                                {
+                                    IRequest request = sentRequest as IRequest;
+                                    result.Action = request.Action;
+
+                                    result.Message = sentRequest;
+                                    result.ReceivedErrorCode = string.Format("ErrorMsg {0}:{1}", ((CallErrorMessage)msg).ErrorCode, ((CallErrorMessage)msg).ErrorDescription);
+                                }
+
+
+                            }
+                            break;
+                        default:
+                            break;
+
+                    }
+
+                    // if (msg != null) Console.WriteLine(string.Format("Receieved Message : {0}", msg.ToString()));
+
+                }
+            }
+            catch (Exception ex)
+            {
+                if (string.IsNullOrEmpty(result.UUID))
+                {
+                    result.UUID = data.Substring(4, 39);
+                    result.UUID = result.UUID.Split(new string[] { "\"," }, StringSplitOptions.None)[0];
+                }
+                result.Success = false;
+                result.Exception = ex;
+            }
+            return result;
+        }
+
+        #region 解析收到的訊息
+        /// <summary>
+        /// Parse data to OCPP Basic Message
+        /// </summary>
+        /// <param name="message"></param>
+        /// <returns></returns>
+        private BaseMessage Parse(string message)
+        {
+            try
+            {
+                if (message.StartsWith("[4,\""))
+                {
+                    message = message.Replace('{', '"');
+                    message = message.Replace('}', '"');
+                }
+                var array = JsonConvert.DeserializeObject<JArray>(message);
+                BaseMessage msg = null;
+                switch ((int)array[INDEX_MESSAGEID])
+                {
+                    case TYPENUMBER_CALL:
+                        {
+                            CallMessage call = new CallMessage();
+                            call.Action = array[INDEX_CALL_ACTION].ToString();
+                            call.Payload = array[INDEX_CALL_PAYLOAD].ToString().Replace("\r\n", "");
+                            msg = call;
+                        }
+                        break;
+                    case TYPENUMBER_CALLRESULT:
+                        {
+                            CallResultMessage callResult = new CallResultMessage();
+                            callResult.Payload = array[INDEX_CALLRESULT_PAYLOAD].ToString().Replace("\r\n", "");
+                            msg = callResult;
+                        }
+                        break;
+                    case TYPENUMBER_CALLERROR:
+                        {
+                            CallErrorMessage callError = new CallErrorMessage();
+                            callError.ErrorCode = array[INDEX_CALLERROR_ERRORCODE].ToString();
+                            callError.ErrorDescription = array[INDEX_CALLERROR_DESCRIPTION].ToString();
+                            callError.ErrorDetails = array[INDEX_CALLERROR_PAYLOAD].ToString().Replace("\r\n", "");
+                            msg = callError;
+                        }
+                        break;
+                    default:
+                        throw new Exception("Message Type notSupported");
+
+
+                }
+                msg.Id = array[INDEX_UNIQUEID].ToString();
+                return msg;
+            }
+            catch (Exception ex)
+            {
+                throw new Exception(string.Format("Parse Error=>  Problem: {0}", ex.Message));
+
+            }
+
+
+
+        }
+
+
+        private BasicMessageResult UnPackPayloadbyCall(string action, string payload)
+        {
+            BasicMessageResult result = new BasicMessageResult();
+            try
+            {
+                Feature feature = null;
+                foreach (var profile in profiles)
+                {
+                    feature = profile.GetFeaturebyAction(action);
+                    if (feature == null)
+                    {
+                        continue;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+
+                result.Request = JsonConvert.DeserializeObject(payload, feature.GetRequestType()) as IRequest;
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+                logger.Error(string.Format("[{0}]UnPackPayloadbyCall Ex: {1}", action, ex.Message), "UnPack");
+
+            }
+
+            return result;
+        }
+
+        private BasicMessageResult UnPackPayloadbyCallResult(Queue requestQueue, string uniqueId, string payload)
+        {
+            int i = 1;
+            BasicMessageResult result = new BasicMessageResult();
+            try
+            {
+                i = -1 ;
+                IRequest request = requestQueue.RestoreRequest(uniqueId);
+
+                if (request == null)
+                {
+                    result.Exception = new Exception("Can't find request");
+                    return result;
+                }
+                i = 2;
+                Feature feature = null;
+                foreach (var profile in profiles)
+                {
+                    i = 3;
+                    feature = profile.GetFeaturebyType(request.GetType());
+                    i = 4;
+                    if (feature == null)
+                    {
+                        continue;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+                i = 5;
+                IConfirmation confrim = JsonConvert.DeserializeObject(payload, feature.GetConfirmationType()) as IConfirmation;
+                i = 6;
+                confrim.SetRequest(request);
+                i = 7;
+                result.Confirmation = confrim;
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+                logger.Error(string.Format(i+"UnPackPayloadbyCallResult Data:[{0},{1}] Ex: {2}", uniqueId, payload, ex.ToString()), "UnPack");
+
+            }
+            return result;
+
+        }
+
+        private IRequest UnPackPayloadbyCallError(Queue requestQueue, string uniqueId)
+        {
+            IRequest sentMsg = requestQueue.RestoreRequest(uniqueId);
+
+            return sentMsg;
+
+        }
+        #endregion
+
+
+    }
+}
+

+ 297 - 0
EVCB_OCPP.WSServer.backup/Message/OCPP20MessageHandler.cs

@@ -0,0 +1,297 @@
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.Basic;
+using EVCB_OCPP20.Packet.Features;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using NLog;
+using OCPPServer.Protocol;
+using System;
+using I20Confirmation = EVCB_OCPP20.Packet.Messages.IConfirmation;
+using I20Request = EVCB_OCPP20.Packet.Messages.IRequest;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    /// <summary>
+    /// 實現 OCPP20 基本傳送規範,
+    /// 1.訊息 基本格式,將訊息包裝成 Call 、CallResult、CallError 三種格式
+    /// 2.OCPP 定義的傳送規則:交易相關的訊息必須依照時序性傳送,一個傳完才能接著送下一個(忽略規則 由Center System定義)
+    /// </summary>
+    internal class OCPP20MessageHandler
+    {
+        static protected ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+
+        #region 傳送 or 解析訊息需要欄位
+        private const int INDEX_MESSAGEID = 0;
+        private const int INDEX_UNIQUEID = 1;
+        internal const int TYPENUMBER_CALL = 2;
+        private const int INDEX_CALL_ACTION = 2;
+        private const int INDEX_CALL_PAYLOAD = 3;
+
+        internal const int TYPENUMBER_CALLRESULT = 3;
+        private const int INDEX_CALLRESULT_PAYLOAD = 2;
+
+        internal const int TYPENUMBER_CALLERROR = 4;
+        private const int INDEX_CALLERROR_ERRORCODE = 2;
+        private const int INDEX_CALLERROR_DESCRIPTION = 3;
+        private const int INDEX_CALLERROR_PAYLOAD = 4;
+
+        private const string CALL_FORMAT = "[2,\"{0}\",\"{1}\",{2}]";
+        private const string CALLRESULT_FORMAT = "[3,\"{0}\",{1}]";
+        private const string CALLERROR_FORMAT = "[4,\"{0}\",\"{1}\",\"{2}\",{3}]";
+        private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+        private const string DATE_FORMAT_WITH_MS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+        #endregion
+
+
+
+
+        /// <summary>
+        /// 將收到的封包做基本的拆解分成 Call 、CallResult、CallError
+        /// </summary>
+        /// <param name="client"></param>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        internal MessageResult AnalysisReceiveData(ClientData client, string data)
+        {
+            MessageResult result = new MessageResult();
+            try
+            {
+
+                var msg = Parse(data);
+                if (msg != null)
+                {
+
+                    result.UUID = msg.Id;
+                    switch (msg.TypeId)
+                    {
+                        case TYPENUMBER_CALL:
+                            {
+                                //只有CallMessage 才有在RawData有Action
+                                BasicMessageResult baseResult = UnPackPayloadbyCall(msg.Action, msg.Payload.ToString());
+                                Actions action = Actions.None;
+                                Enum.TryParse<Actions>(msg.Action, out action);
+                                result.Action = msg.Action;
+                                if (baseResult.Request20 != null)
+                                {
+                                    if (baseResult.Request20.Validate())
+                                    {
+                                        result.Id = TYPENUMBER_CALL;
+                                        result.Message = baseResult.Request20;
+
+                                    }
+                                    else
+                                    {
+
+                                        string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
+                                             OCPPErrorDescription.OccurenceConstraintViolation);
+                                        result.Id = TYPENUMBER_CALL;
+                                        result.Message = baseResult.Request20;
+                                        result.Success = false;
+                                        result.CallErrorMsg = replyMsg;
+                                        result.Exception = new Exception("Validation Failed");
+
+                                    }
+                                }
+                                else
+                                {
+
+                                    string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation, OCPPErrorDescription.OccurenceConstraintViolation);
+                                    result.Id = TYPENUMBER_CALL;
+                                    result.Message = baseResult.Request20;
+                                    result.Success = false;
+                                    result.CallErrorMsg = replyMsg;
+                                    result.Exception = baseResult.Exception;
+                                }
+
+                            }
+                            break;
+                        case TYPENUMBER_CALLRESULT:
+                            {
+                                BasicMessageResult baseResult = UnPackPayloadbyCallResult(client.queue20, msg.Id, msg.Payload.ToString());
+
+                                if (baseResult.Confirmation20 != null)
+                                {
+
+                                    if (baseResult.Confirmation20.Validate())
+                                    {
+                                        result.Id = TYPENUMBER_CALLRESULT;
+                                        result.Message = baseResult.Confirmation20;
+                                        result.Action = baseResult.Confirmation20.GetRequest().Action;
+                                        //return data
+                                    }
+                                    else
+                                    {
+                                        string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
+                                      OCPPErrorDescription.OccurenceConstraintViolation);
+                                        result.Id = TYPENUMBER_CALLRESULT;
+                                        result.Message = baseResult.Confirmation20;
+                                        result.Success = false;
+                                        result.CallErrorMsg = replyMsg;
+                                        result.Exception = new Exception("Validate Failed");
+                                    }
+                                }
+                                else
+                                {
+                                    string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
+                                   OCPPErrorDescription.OccurenceConstraintViolation);
+                                    result.Id = TYPENUMBER_CALLRESULT;
+                                    result.Message = baseResult.Confirmation20;
+                                    result.Success = false;
+                                    result.CallErrorMsg = replyMsg;
+                                    result.Exception = baseResult.Exception;
+                                }
+
+                            }
+                            break;
+                        case TYPENUMBER_CALLERROR:
+                            {
+                                result.Id = TYPENUMBER_CALLERROR;
+                                // var sentRequest = UnPackPayloadbyCallError(client.queue, msg.Id);
+
+                                //if (sentRequest != null)
+                                //{
+                                //    I20Request request = sentRequest as I20Request;
+                                //    result.Action = request.Action;
+
+                                //    result.Message = sentRequest;
+                                //    result.ReceivedErrorCode = string.Format("ErrorMsg {0}:{1}", ((CallErrorMessage)msg).ErrorCode, ((CallErrorMessage)msg).ErrorDescription);
+                                //}
+
+
+                            }
+                            break;
+                        default:
+                            break;
+
+                    }
+
+                    // if (msg != null) Console.WriteLine(string.Format("Receieved Message : {0}", msg.ToString()));
+
+                }
+            }
+            catch (Exception ex)
+            {
+                if (string.IsNullOrEmpty(result.UUID))
+                {
+                    result.UUID = data.Substring(4, 39);
+                    result.UUID = result.UUID.Split(new string[] { "\"," }, StringSplitOptions.None)[0];
+                }
+                result.Success = false;
+                result.Exception = ex;
+            }
+            return result;
+        }
+
+        #region 解析收到的訊息
+        /// <summary>
+        /// Parse data to OCPP Basic Message
+        /// </summary>
+        /// <param name="message"></param>
+        /// <returns></returns>
+        private BaseMessage Parse(string message)
+        {
+            try
+            {
+                if (message.StartsWith("[4,\""))
+                {
+                    message = message.Replace('{', '"');
+                    message = message.Replace('}', '"');
+                }
+                var array = JsonConvert.DeserializeObject<JArray>(message);
+                BaseMessage msg = null;
+                switch ((int)array[INDEX_MESSAGEID])
+                {
+                    case TYPENUMBER_CALL:
+                        {
+                            CallMessage call = new CallMessage();
+                            call.Action = array[INDEX_CALL_ACTION].ToString();
+                            call.Payload = array[INDEX_CALL_PAYLOAD].ToString().Replace("\r\n", "");
+                            msg = call;
+                        }
+                        break;
+                    case TYPENUMBER_CALLRESULT:
+                        {
+                            CallResultMessage callResult = new CallResultMessage();
+                            callResult.Payload = array[INDEX_CALLRESULT_PAYLOAD].ToString().Replace("\r\n", "");
+                            msg = callResult;
+                        }
+                        break;
+                    case TYPENUMBER_CALLERROR:
+                        {
+                            CallErrorMessage callError = new CallErrorMessage();
+                            callError.ErrorCode = array[INDEX_CALLERROR_ERRORCODE].ToString();
+                            callError.ErrorDescription = array[INDEX_CALLERROR_DESCRIPTION].ToString();
+                            callError.ErrorDetails = array[INDEX_CALLERROR_PAYLOAD].ToString().Replace("\r\n", "");
+                            msg = callError;
+                        }
+                        break;
+                    default:
+                        throw new Exception("Message Type notSupported");
+
+
+                }
+                msg.Id = array[INDEX_UNIQUEID].ToString();
+                return msg;
+            }
+            catch (Exception ex)
+            {
+                throw new Exception(string.Format("Parse Error=> {0} Problem: {0}", message, ex.Message));
+
+            }
+
+
+
+        }
+
+
+        private BasicMessageResult UnPackPayloadbyCall(string action, string payload)
+        {
+
+            BasicMessageResult result = new BasicMessageResult();
+            try
+            {
+
+                result.Request20 = (I20Request)(JsonConvert.DeserializeObject(payload, Type.GetType("EVCB_OCPP20.Packet.Messages." + action + "Request,EVCB_OCPP20.Packet")));
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+                logger.Error(string.Format("[{0}]UnPackPayloadbyCall Ex: {1}", action, ex.Message), "UnPack");
+
+            }
+
+            return result;
+
+
+        }
+
+        private BasicMessageResult UnPackPayloadbyCallResult(EVCB_OCPP20.Packet.Messages.Basic.Queue requestQueue, string uniqueId, string payload)
+        {
+            BasicMessageResult result = new BasicMessageResult();
+            try
+            {
+                I20Request request = requestQueue.RestoreRequest(uniqueId);
+                I20Confirmation confrim = JsonConvert.DeserializeObject(payload, Type.GetType("EVCB_OCPP20.Packet.Messages." + request.Action + "Response,EVCB_OCPP20.Packet")) as I20Confirmation;
+                confrim.SetRequest(request);
+                result.Confirmation20 = confrim;
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+                logger.Error(string.Format("UnPackPayloadbyCallResult Data:[{0},{1}] Ex: {2}", uniqueId, payload, ex.ToString()), "UnPack");
+
+            }
+            return result;
+
+        }
+
+
+
+        #endregion
+
+
+
+    }
+}

+ 86 - 0
EVCB_OCPP.WSServer.backup/Message/RemoteTriggerHandler.cs

@@ -0,0 +1,86 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.RemoteTrigger;
+using OCPPServer.Protocol;
+using System;
+using System.Linq;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal partial class ProfileHandler
+    {
+
+
+        internal MessageResult ExecuteRemoteTriggerConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.TriggerMessage:
+                    {
+                        TriggerMessageConfirmation _confirm = confirm as TriggerMessageConfirmation;
+                        TriggerMessageRequest _request = _confirm.GetRequest() as TriggerMessageRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = _confirm.status.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.RemoteTrigger.", "")));
+                    }
+                    break;
+            }
+            return result;
+        }
+
+
+        internal MessageResult ReceivedRemoteTriggerError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.TriggerMessage:
+                    {
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+    }
+}

+ 125 - 0
EVCB_OCPP.WSServer.backup/Message/ReservationProfileHandler.cs

@@ -0,0 +1,125 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.Reservation;
+using OCPPServer.Protocol;
+using System;
+using System.Linq;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal partial class ProfileHandler
+    {
+
+
+        internal MessageResult ExecuteReservationConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.ReserveNow:
+                    {
+                        ReserveNowConfirmation _confirm = confirm as ReserveNowConfirmation;
+                        ReserveNowRequest _request = _confirm.GetRequest() as ReserveNowRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = _confirm.status.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                case Actions.CancelReservation:
+                    {
+                        CancelReservationConfirmation _confirm = confirm as CancelReservationConfirmation;
+                        CancelReservationRequest _request = _confirm.GetRequest() as CancelReservationRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = _confirm.status.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.RemoteTrigger.", "")));
+                    }
+                    break;
+            }
+            return result;
+        }
+
+
+        internal MessageResult ExecuteReservationError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.ReserveNow:
+                    {
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                case Actions.CancelReservation:
+                    {
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+    }
+}

+ 73 - 0
EVCB_OCPP.WSServer.backup/Message/SecurityProfileHandler.cs

@@ -0,0 +1,73 @@
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using OCPPServer.Protocol;
+using System;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal partial class ProfileHandler
+    {
+        internal MessageResult ExecuteSecurityRequest(Actions action, ClientData session, IRequest request)
+        {
+            MessageResult result = new MessageResult() { Success = false };
+
+            try
+            {
+                switch (action)
+                {
+
+
+                    default:
+                        {
+                            Console.WriteLine(string.Format("Not Implement {0} Logic(ExecuteCoreRequest)", request.GetType().ToString().Replace("OCPPPackage.Messages.Core.", "")));
+                        }
+                        break;
+                }
+            }
+            catch (Exception ex)
+            {
+                logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action));
+                logger.Fatal(string.Format("Data {0}", request.ToString()));
+                logger.Fatal(string.Format("Error {0}", ex.ToString()));
+                result.Exception = ex;
+            }
+
+
+
+            return result;
+        }
+        internal MessageResult ExecuteSecurityConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = false };
+
+            switch (action)
+            {
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.RemoteTrigger.", "")));
+                    }
+                    break;
+            }
+            return result;
+        }
+
+
+        internal MessageResult ReceivedSecurityError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+    }
+}

+ 208 - 0
EVCB_OCPP.WSServer.backup/Message/SmartChargingProfileHandler.cs

@@ -0,0 +1,208 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Domain.Models.Database;
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.SmartCharging;
+using EVCB_OCPP.Packet.Messages.SubTypes;
+using Newtonsoft.Json;
+using OCPPServer.Protocol;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace EVCB_OCPP.WSServer.Message
+{
+    internal partial class ProfileHandler
+    {
+
+
+        internal void SetChargingProfile(string chargeBoxId, decimal value, ChargingRateUnitType unit)
+        {
+            using (var db = new MainDBContext())
+            {
+                var _setProfileRequest = new SetChargingProfileRequest()
+                {
+                    connectorId = 0,
+                    csChargingProfiles = new Packet.Messages.SubTypes.csChargingProfiles()
+                    {
+                        chargingProfileId = 1,
+                        chargingProfileKind = Packet.Messages.SubTypes.ChargingProfileKindType.Recurring,
+                        chargingProfilePurpose = Packet.Messages.SubTypes.ChargingProfilePurposeType.ChargePointMaxProfile,
+                        chargingSchedule = new Packet.Messages.SubTypes.ChargingSchedule()
+                        {
+                            chargingRateUnit = unit,
+                            chargingSchedulePeriod = new List<Packet.Messages.SubTypes.ChargingSchedulePeriod>()
+                                                    {
+                                                        new Packet.Messages.SubTypes.ChargingSchedulePeriod(){  startPeriod=0, limit=value*1000}
+                                                    },
+                            duration = 60,
+
+                        },
+                        recurrencyKind = Packet.Messages.SubTypes.RecurrencyKindType.Daily,
+                        stackLevel = 1,
+
+                    }
+                };
+
+                db.ServerMessage.Add(new ServerMessage()
+                {
+                    ChargeBoxId = chargeBoxId,
+                    CreatedBy = "Server",
+                    CreatedOn = DateTime.UtcNow,
+                    OutAction = _setProfileRequest.Action.ToString(),
+                    OutRequest = JsonConvert.SerializeObject(_setProfileRequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                    SerialNo = Guid.Empty.ToString(),
+                    InMessage = string.Empty
+
+                });
+                db.SaveChanges();
+            }
+        }
+
+
+        internal void ClearChargingProfile(string chargeBoxId)
+        {
+            using (var db = new MainDBContext())
+            {
+                var _clearProfileRequest = new ClearChargingProfileRequest()
+                {
+                    connectorId = 0,
+                    chargingProfilePurpose = ChargingProfilePurposeType.ChargePointMaxProfile,
+
+                };
+
+                db.ServerMessage.Add(new ServerMessage()
+                {
+                    ChargeBoxId = chargeBoxId,
+                    CreatedBy = "Server",
+                    CreatedOn = DateTime.UtcNow,
+                    OutAction = _clearProfileRequest.Action.ToString(),
+                    OutRequest = JsonConvert.SerializeObject(_clearProfileRequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                    SerialNo = Guid.Empty.ToString(),
+                    InMessage = string.Empty
+
+                });
+
+                db.SaveChanges();
+            }
+        }
+
+
+
+
+
+        internal MessageResult ExecuteSmartChargingConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.ClearChargingProfile:
+
+                    {
+                        ClearChargingProfileConfirmation _confirm = confirm as ClearChargingProfileConfirmation;
+                        ClearChargingProfileRequest _request = _confirm.GetRequest() as ClearChargingProfileRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = _confirm.status.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                case Actions.SetChargingProfile:
+                    {
+                        SetChargingProfileConfirmation _confirm = confirm as SetChargingProfileConfirmation;
+                        SetChargingProfileRequest _request = _confirm.GetRequest() as SetChargingProfileRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = _confirm.status.ToString();
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                case Actions.GetCompositeSchedule:
+                    {
+                        GetCompositeScheduleConfirmation _confirm = confirm as GetCompositeScheduleConfirmation;
+                        GetCompositeScheduleRequest _request = _confirm.GetRequest() as GetCompositeScheduleRequest;
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)_confirm.status;//OK
+                                operation.EVSE_Value = JsonConvert.SerializeObject(_confirm.chargingSchedule, Formatting.None);
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.RemoteTrigger.", "")));
+                    }
+                    break;
+            }
+            return result;
+        }
+
+
+        internal MessageResult ReceivedSmartChargingError(Actions action, string errorMsg, ClientData session, string requestId)
+        {
+            MessageResult result = new MessageResult() { Success = true };
+
+            switch (action)
+            {
+                case Actions.ClearChargingProfile:
+                case Actions.SetChargingProfile:
+                case Actions.GetCompositeSchedule:
+                    {
+                        using (var db = new MainDBContext())
+                        {
+                            var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
+                            x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
+                            if (operation != null)
+                            {
+                                operation.FinishedOn = DateTime.UtcNow;
+                                operation.Status = 1;//電樁有回覆
+                                operation.EVSE_Status = (int)255;//錯誤
+                                operation.EVSE_Value = errorMsg;
+                                db.SaveChanges();
+                            }
+
+                        }
+                    }
+                    break;
+
+                default:
+                    {
+                        Console.WriteLine(string.Format("Not Implement {0} Logic", action));
+                    }
+                    break;
+            }
+            return result;
+
+        }
+    }
+}

+ 0 - 0
EVCB_OCPP.WSServer/NLog.config → EVCB_OCPP.WSServer.backup/NLog.config


+ 0 - 0
EVCB_OCPP.WSServer/NLog.xsd → EVCB_OCPP.WSServer.backup/NLog.xsd


+ 46 - 0
EVCB_OCPP.WSServer.backup/Program.cs

@@ -0,0 +1,46 @@
+using Newtonsoft.Json;
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer
+{
+   
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            Console.WriteLine("====================================================================================================");
+            Console.WriteLine("====================================================================================================");
+            Console.WriteLine("==                                                                                                ==");
+            Console.WriteLine("==       ------------               -----------      -------------         -------------          ==");
+            Console.WriteLine("==    ---            ---       ----                  ----------------      ----------------       ==");
+            Console.WriteLine("==    ---            ---     ----                    ----            ---   ----            ---    ==");
+            Console.WriteLine("==    ---            ---    ----                     ----            ---   ----            ---    ==");
+            Console.WriteLine("==    ---            ---    ----                     ---- -------------    ---- -------------     ==");
+            Console.WriteLine("==    ---            ---    ----                     ---- -----------      ---- -----------       ==");
+            Console.WriteLine("==    ---            ---      ----                   ----                  ----                   ==");
+            Console.WriteLine("==    ---            ---        ----                 ----                  ----                   ==");
+            Console.WriteLine("==       -----------                -----------      ----                  ----                   ==");
+            Console.WriteLine("==                                                                                                ==");
+            Console.WriteLine("====================================================================================================");
+            Console.WriteLine("====================================================================================================");
+            ProtalServer s = new ProtalServer();
+            Console.WriteLine("Starting Server...");
+            s.Start();
+
+            Console.Read();
+        }
+
+        public static object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+        {
+            DateTime? timevalue = null;
+            if (reader.Value != null)
+            {
+                DateTime date = ((DateTime)reader.Value).ToLocalTime();
+                timevalue = new DateTime(date.Year, date.Month, date.Day, date.TimeOfDay.Hours, date.TimeOfDay.Minutes, date.TimeOfDay.Seconds, 000);
+            }
+            return timevalue;
+        }
+    }
+}

+ 38 - 0
EVCB_OCPP.WSServer.backup/Properties/AssemblyInfo.cs

@@ -0,0 +1,38 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 組件的一般資訊是由下列的屬性集控制。
+// 變更這些屬性的值即可修改組件的相關
+// 資訊。
+[assembly: AssemblyTitle("EVCB_OCPP.WSServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("EVCB_OCPP.WSServer")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 將 ComVisible 設為 false 可對 COM 元件隱藏
+// 組件中的類型。若必須從 COM 存取此組件中的類型,
+// 的類型,請在該類型上將 ComVisible 屬性設定為 true。
+[assembly: ComVisible(false)]
+
+// 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID
+[assembly: Guid("de0c1e9a-1eee-42cc-8a91-73bf9056a7e7")]
+
+// 組件的版本資訊由下列四個值所組成: 
+//
+//      主要版本
+//      次要版本
+//      組建編號
+//      修訂編號
+//
+// 您可以指定所有的值,或將組建編號或修訂編號設為預設值
+// 指定為預設值: 
+// [assembly: AssemblyVersion("1.2.1.0")]
+[assembly: AssemblyVersion("1.2.1.0")]
+[assembly: AssemblyFileVersion("1.2.1.0")]
+
+[assembly: AssemblyInformationalVersion("0bc54e3")]

+ 2171 - 0
EVCB_OCPP.WSServer.backup/ProtalServer.cs

@@ -0,0 +1,2171 @@
+using Dapper;
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Domain.Models.Database;
+using EVCB_OCPP.Packet.Features;
+using EVCB_OCPP.Packet.Messages;
+using EVCB_OCPP.Packet.Messages.Basic;
+using EVCB_OCPP.Packet.Messages.Core;
+using EVCB_OCPP.Packet.Messages.RemoteTrigger;
+using EVCB_OCPP.WSServer.Dto;
+using EVCB_OCPP.WSServer.Helper;
+using EVCB_OCPP.WSServer.Message;
+using EVCB_OCPP.WSServer.Service;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using NLog;
+using OCPPServer.Protocol;
+using OCPPServer.SubProtocol;
+using SuperSocket.SocketBase;
+using SuperSocket.SocketBase.Config;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.Entity;
+using System.Data.SqlClient;
+using System.Diagnostics;
+using System.Linq;
+using System.Security.Authentication;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+
+namespace EVCB_OCPP.WSServer
+{
+    public class DestroyRequest : IRequest
+    {
+        public string Action { get; set; }
+
+        public bool TransactionRelated()
+        {
+            return false;
+        }
+
+        public bool Validate()
+        {
+            return true;
+        }
+    }
+    internal class ProtalServer
+    {
+        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        private OuterHttpClient httpClient = new OuterHttpClient();
+        private DateTime lastcheckdt = DateTime.UtcNow.AddSeconds(-20);
+        private Dictionary<string, ClientData> clientDic = new Dictionary<string, ClientData>();
+        private readonly Object _lockClientDic = new object();
+        private readonly Object _lockConfirmPacketList = new object();
+        private ProfileHandler profileHandler = new ProfileHandler();
+        private List<NeedConfirmMessage> needConfirmPacketList = new List<NeedConfirmMessage>();
+        private DateTime checkUpdateDt = DateTime.UtcNow;
+        private DateTime _CheckFeeDt = DateTime.UtcNow;
+        private DateTime _CheckWeatherDt = DateTime.UtcNow;
+        private LoadingBalanceService _loadingBalanceService = new LoadingBalanceService();
+        private Dictionary<string, TCCWeatherDto> TCCStationDic = new Dictionary<string, TCCWeatherDto>();
+
+        private List<string> needConfirmActions = new List<string>()
+        {
+             "GetConfiguration",
+             "ChangeConfiguration",
+             "RemoteStartTransaction",
+             "RemoteStopTransaction",
+             "ChangeAvailability",
+             "ClearCache",
+             "DataTransfer",
+             "Reset",
+             "UnlockConnector",
+             "TriggerMessage",
+             "GetDiagnostics",
+             "UpdateFirmware",
+             "GetLocalListVersion",
+             "SendLocalList",
+             "SetChargingProfile",
+             "ClearChargingProfile",
+             "GetCompositeSchedule",
+             "ReserveNow",
+             "CancelReservation",
+             "ExtendedTriggerMessage"
+        };
+        private List<Profile> profiles = new List<Profile>()
+        {
+             new CoreProfile(),
+             new FirmwareManagementProfile(),
+             new ReservationProfile(),
+             new RemoteTriggerProfile(),
+             new SmartChargingProfile(),
+             new LocalAuthListManagementProfile(),
+             new SecurityProfile(),
+        };
+        private CancellationTokenSource _cts = new CancellationTokenSource();
+        private CancellationToken _ct;
+        private string _ocpp20NetworkSetting = "";
+
+        internal ProtalServer()
+        {
+            _ct = _cts.Token;
+            WarmUpLog();
+
+
+
+
+        }
+
+
+        internal void Start()
+        {
+
+            if (!GlobalConfig.LoadAPPConfig())
+            {
+                Console.WriteLine("Please check App.Config setting .");
+                return;
+            }
+            //ReadTCCSetting();
+            OpenNetwork();
+
+            Task serverCommandTask = new Task(ServerMessageTrigger, _ct);
+            serverCommandTask.Start();
+
+            Task serverUpdateTask = new Task(ServerUpdateTrigger, _ct);
+            serverUpdateTask.Start();
+
+            Task serverSetFeeTask = new Task(ServerSetFeeTrigger, _ct);
+            serverSetFeeTask.Start();
+
+            Task serverWeatherNotificationTask = new Task(ServerWeatherNotificationTrigger, _ct);
+            serverWeatherNotificationTask.Start();
+
+            Task serverBeatTask = new Task(HeartBeatCheckTrigger, _ct);
+            serverBeatTask.Start();
+
+            Task serverHealthTask = new Task(HealthCheckTrigger, _ct);
+            serverHealthTask.Start();
+
+            while (true)
+            {
+                var input = Console.ReadLine();
+
+                switch (input.ToLower())
+                {
+                    case "stop":
+                        Console.WriteLine("Command stop");
+                        Stop();
+                        break;
+
+                    case "gc":
+                        Console.WriteLine("Command GC");
+                        GC.Collect();
+                        break;
+
+                    case "lc":
+                        {
+                            Console.WriteLine("Command List Clients");
+                            Dictionary<string, ClientData> _copyClientDic = null;
+                            lock (_lockClientDic)
+                            {
+                                _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                            }
+                            var list = _copyClientDic.Select(c => c.Value).ToList();
+                            var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
+                            int i = 1;
+                            foreach (var c in list)
+                            {
+                                Console.WriteLine(i + ":" + c.ChargeBoxId + " " + c.SessionID);
+                                i++;
+                            }
+
+                            foreach (var c in TCCStationDic)
+                            {
+                                Console.WriteLine(i + ":" + c.Key + "-" + c.Value.Temperature + "/" + c.Value.WeatherID);
+                                i++;
+                            }
+
+                        }
+                        break;
+                    case "lcn":
+                        {
+                            Console.WriteLine("Command List Customer Name");
+                            Dictionary<string, ClientData> _copyClientDic = null;
+                            lock (_lockClientDic)
+                            {
+                                _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                            }
+                            var lcn = clientDic.Select(c => c.Value.CustomerName).Distinct().ToList();
+                            int iLcn = 1;
+                            foreach (var c in lcn)
+                            {
+                                Console.WriteLine(iLcn + ":" + c + ":" + clientDic.Where(z => z.Value.CustomerName == c).Count().ToString());
+                                iLcn++;
+                            }
+
+                        }
+                        break;
+                    case "help":
+                        Console.WriteLine("Command help!!");
+                        Console.WriteLine("lcn : List Customer Name");
+                        Console.WriteLine("gc : GC Collect");
+                        Console.WriteLine("lc : List Clients");
+                        Console.WriteLine("cls : clear console");
+                        Console.WriteLine("silent : silent");
+                        Console.WriteLine("show : show log");
+                        // logger.Info("rcl : show Real Connection Limit");
+                        break;
+                    case "cls":
+                        Console.WriteLine("Command clear");
+                        Console.Clear();
+                        break;
+
+                    case "silent":
+                        Console.WriteLine("Command silent");
+                        var xe = XElement.Load("NLog.config");
+                        var xns = xe.GetDefaultNamespace();
+                        var minlevelattr = xe.Descendants(xns + "rules").Elements(xns + "logger")
+                            .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
+                        if (minlevelattr != null)
+                        {
+
+                            minlevelattr.Value = "Warn";
+                        }
+                        xe.Save("NLog.config");
+                        break;
+                    case "show":
+                        Console.WriteLine("Command show");
+                        var xe1 = XElement.Load("NLog.config");
+                        var xns1 = xe1.GetDefaultNamespace();
+                        var minlevelattr1 = xe1.Descendants(xns1 + "rules").Elements(xns1 + "logger")
+                            .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
+                        if (minlevelattr1 != null)
+                        {
+
+                            minlevelattr1.Value = "trace";
+                        }
+                        xe1.Save("NLog.config");
+                        break;
+                    case "rcl":
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        internal void Stop()
+        {
+            if (_cts != null)
+            {
+                _cts.Cancel();
+            }
+        }
+
+        private void CheckVersion(string chargeBoxId)
+        {
+            if (string.IsNullOrEmpty(chargeBoxId)) return;
+            using (var db = new MainDBContext())
+            {
+                db.ServerMessage.Add(new ServerMessage()
+                {
+                    ChargeBoxId = chargeBoxId,
+                    CreatedBy = "Server",
+                    CreatedOn = DateTime.UtcNow,
+                    OutAction = Actions.DataTransfer.ToString(),
+                    OutRequest = JsonConvert.SerializeObject(
+                          new DataTransferRequest()
+                          {
+                              messageId = "ID_FirmwareVersion",
+                              vendorId = "Phihong Technology"
+
+                          },
+                          new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                    SerialNo = Guid.NewGuid().ToString(),
+                    InMessage = string.Empty
+
+                });
+
+                db.SaveChanges();
+            }
+
+        }
+
+
+        private void CheckEVSEConfigure(string chargeBoxId)
+        {
+            if (string.IsNullOrEmpty(chargeBoxId)) return;
+            using (var db = new MainDBContext())
+            {
+                db.ServerMessage.Add(new ServerMessage()
+                {
+                    ChargeBoxId = chargeBoxId,
+                    CreatedBy = "Server",
+                    CreatedOn = DateTime.UtcNow,
+                    OutAction = Actions.GetConfiguration.ToString(),
+                    OutRequest = JsonConvert.SerializeObject(
+                            new GetConfigurationRequest()
+                            {
+                                key = new List<string>()
+
+                            },
+                            new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                    SerialNo = Guid.NewGuid().ToString(),
+                    InMessage = string.Empty
+
+                }); ;
+
+                db.SaveChanges();
+
+            }
+        }
+
+
+        #region 台泥
+
+
+        private void ReadTCCSetting()
+        {
+            using (var db = new MainDBContext())
+            {
+                var info = db.Customer.Where(x => x.Id == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).Select(x => new { x.ApiUrl, x.ApiKey }).FirstOrDefault();
+                GlobalConfig.TCC_API_URL = info.ApiUrl;
+                GlobalConfig.TCC_SALTKEY = info.ApiKey;
+
+            }
+        }
+        async private Task<TCCStationInfoDto> GetStationInfo(string machineId)
+        {
+            TCCStationInfoDto stationInfo = null;
+            if (string.IsNullOrEmpty(machineId)) return stationInfo;
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                string sql = " SELECT CAST([Latitude] as DECIMAL(5,2)) Lat,CAST([Longitude] as DECIMAL(5, 2))  Long ,SUBSTRING([Address],1,3) as zipcode FROM[StationMachine]  left join [dbo].[Station]" +
+               "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId; ";
+
+                var result = await conn.QueryAsync<TCCStationInfoDto>(sql, parameters);
+                stationInfo = result.FirstOrDefault();
+            }
+
+            return stationInfo;
+        }
+        #endregion
+
+        private void OpenNetwork()
+        {
+
+            //載入OCPP Protocol
+            var appServer = new OCPPWSServer(new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") });
+
+            List<IListenerConfig> llistener = new List<IListenerConfig>();
+
+            llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWS_Port()), Backlog = 100, Security = "None" });
+            llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWSS_Port()), Backlog = 100, Security = SslProtocols.Tls12.ToString() });
+
+            var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource;
+            ICertificateConfig Certificate = config.Servers.ElementAt(0).Certificate;
+            IEnumerable<IListenerConfig> listeners = llistener;
+
+            //設定server config
+            var serverConfig = new ServerConfig
+            {
+                //Port = Convert.ToInt32(2012),
+                //Ip = "172.17.40.13",
+                MaxRequestLength = 204800,
+                //Security = serverSecurity,
+                Certificate = Certificate,
+                Listeners = listeners,
+                //  LogAllSocketException = true,
+                KeepAliveTime = 10,
+                // LogBasicSessionActivity = true
+            };
+
+            //Setup with listening port
+            if (!appServer.Setup(serverConfig, logFactory: new OCPPLogFactory()))
+            {
+                Console.WriteLine("Failed to setup!");
+                return;
+            }
+
+            appServer.NewSessionConnected += AppServer_NewSessionConnected;
+            appServer.SessionClosed += AppServer_SessionClosed;
+
+
+            //Try to start the appServer
+            if (!appServer.Start())
+            {
+                Console.WriteLine("Failed to start!");
+                Console.ReadKey();
+                return;
+            }
+        }
+
+        private void AppServer_SessionClosed(ClientData session, CloseReason value)
+        {
+            WriteMachineLog(session, string.Format("CloseReason: {0}", value), "Connection", "");
+            RemoveClient(session);
+        }
+
+        private void AppServer_NewSessionConnected(ClientData session)
+        {
+            logger.Debug(string.Format("{0} NewSessionConnected", session.Path));
+
+            try
+            {
+                lock (_lockClientDic)
+                {
+                    bool isNotSupported = session.SecWebSocketProtocol.Contains("ocpp1.6") ? false : session.SecWebSocketProtocol.Contains("ocpp2.0") ? false : true;
+                    if (isNotSupported)
+                    {
+                        //logger.Debug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol));
+                        WriteMachineLog(session, string.Format("SecWebSocketProtocol:{0} NotSupported", session.SecWebSocketProtocol), "Connection", "");
+                        return;
+                    }
+                    ClientData _removeClient = null;
+
+
+                    clientDic.TryGetValue(session.ChargeBoxId, out _removeClient);
+                    if (_removeClient != null)
+                    {
+                        WriteMachineLog(_removeClient, "Duplicate Logins", "Connection", "");
+                        _removeClient.Close(CloseReason.ServerShutdown);
+                        RemoveClient(_removeClient);
+                    }
+
+                    clientDic.Add(session.ChargeBoxId, session);
+                    session.m_ReceiveData += new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
+                    // logger.Debug("------------New " + (session == null ? "Oops" : session.ChargeBoxId));
+                    WriteMachineLog(session, "NewSessionConnected", "Connection", "");
+
+                    using (var db = new MainDBContext())
+                    {
+                        var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+                        if (machine != null)
+                        {
+                            machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1;
+                            db.SaveChanges();
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                logger.Error(string.Format("NewSessionConnected Ex: {0}", ex.ToString()));
+            }
+
+
+        }
+
+        async private void ReceivedMessage(ClientData session, string rawdata)
+        {
+            try
+            {
+                BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                MessageResult analysisResult = msgAnalyser.AnalysisReceiveData(session, rawdata);
+
+                WriteMachineLog(session, rawdata,
+                     string.Format("{0} {1}", string.IsNullOrEmpty(analysisResult.Action) ? "unknown" : analysisResult.Action, analysisResult.Id == 2 ? "Request" : (analysisResult.Id == 3 ? "Confirmation" : "Error")), analysisResult.Exception == null ? "" : analysisResult.Exception.Message);
+
+                if (session.ResetSecurityProfile)
+                {
+                    logger.Error(string.Format("[{0}] ChargeBoxId:{1} ResetSecurityProfile", DateTime.UtcNow, session.ChargeBoxId));
+                    RemoveClient(session);
+                    return;
+                }
+
+
+                if (!analysisResult.Success)
+                {
+                    //解析RawData就發生錯誤
+                    if (!string.IsNullOrEmpty(analysisResult.CallErrorMsg))
+                    {
+                        Send(session, analysisResult.CallErrorMsg, string.Format("{0} {1}", analysisResult.Action, "Error"));
+                    }
+                    else
+                    {
+                        if (analysisResult.Message == null)
+                        {
+                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Empty;
+                            if (analysisResult.Exception != null)
+                            {
+                                errorMsg = analysisResult.Exception.ToString();
+                            }
+
+                            Send(session, replyMsg, string.Format("{0} {1}", "unknown", "Error"), "EVSE's sent essage has parsed Failed. ");
+                        }
+                        else
+                        {
+                            BaseMessage _baseMsg = analysisResult.Message as BaseMessage;
+
+
+                            string replyMsg = BasicMessageHandler.GenerateCallError(_baseMsg.Id, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Empty;
+                            if (analysisResult.Exception != null)
+                            {
+                                errorMsg = analysisResult.Exception.ToString();
+                            }
+
+                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                        }
+
+                    }
+                }
+                else
+                {
+                    switch (analysisResult.Id)
+                    {
+                        case BasicMessageHandler.TYPENUMBER_CALL:
+                            {
+                                if (!session.ISOCPP20)
+                                {
+                                    Actions action = Convertor.GetAction(analysisResult.Action);
+                                    ProcessRequestMessage(analysisResult, session, action);
+                                }
+                                else
+                                {
+                                    EVCB_OCPP20.Packet.Features.Actions action = Convertor.GetActionby20(analysisResult.Action);
+                                    MessageResult result = new MessageResult() { Success = true };
+                                    //ocpp20 處理
+                                    switch (action)
+                                    {
+
+                                        case EVCB_OCPP20.Packet.Features.Actions.BootNotification:
+                                            {
+                                                EVCB_OCPP20.Packet.Messages.BootNotificationRequest _request = (EVCB_OCPP20.Packet.Messages.IRequest)analysisResult.Message as EVCB_OCPP20.Packet.Messages.BootNotificationRequest;
+
+                                                var confirm = new EVCB_OCPP20.Packet.Messages.BootNotificationResponse() { CurrentTime = DateTime.UtcNow, Interval = 180, Status = EVCB_OCPP20.Packet.DataTypes.EnumTypes.RegistrationStatusEnumType.Pending };
+
+                                                result.Message = confirm;
+                                                result.Success = true;
+
+                                                string response = BasicMessageHandler.GenerateConfirmationofOCPP20(analysisResult.UUID, (EVCB_OCPP20.Packet.Messages.IConfirmation)result.Message);
+                                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Response"), result.Exception == null ? string.Empty : result.Exception.ToString());
+
+
+                                                var request = new EVCB_OCPP20.Packet.Messages.SetNetworkProfileRequest()
+                                                {
+                                                    ConfigurationSlot = 1,
+                                                    ConnectionData = new EVCB_OCPP20.Packet.DataTypes.NetworkConnectionProfileType()
+                                                    {
+                                                        OcppVersion = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPVersionEnumType.OCPP20,
+                                                        OcppTransport = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPTransportEnumType.JSON,
+                                                        MessageTimeout = 30,
+                                                        OcppCsmsUrl = session.UriScheme == "ws" ? GlobalConfig.OCPP20_WSUrl : GlobalConfig.OCPP20_WSSUrl,
+                                                        OcppInterface = EVCB_OCPP20.Packet.DataTypes.EnumTypes.OCPPInterfaceEnumType.Wired0
+                                                    }
+
+                                                };
+                                                var uuid = session.queue20.store(request);
+                                                string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "SetNetworkProfile", request);
+                                                Send(session, requestText, "SetNetworkProfile");
+
+                                            }
+                                            break;
+                                        default:
+                                            {
+                                                logger.Error(string.Format("We don't implement messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
+                                            }
+                                            break;
+                                    }
+
+                                }
+                            }
+                            break;
+                        case BasicMessageHandler.TYPENUMBER_CALLRESULT:
+                            {
+                                if (!session.ISOCPP20)
+                                {
+                                    Actions action = Convertor.GetAction(analysisResult.Action);
+                                    ProcessConfirmationMessage(analysisResult, session, action);
+                                }
+                                else
+                                {
+                                    EVCB_OCPP20.Packet.Features.Actions action = Convertor.GetActionby20(analysisResult.Action);
+                                    MessageResult result = new MessageResult() { Success = true };
+                                    //ocpp20 處理
+                                    switch (action)
+                                    {
+
+                                        case EVCB_OCPP20.Packet.Features.Actions.SetNetworkProfile:
+                                            {
+                                                EVCB_OCPP20.Packet.Messages.SetNetworkProfileResponse response = (EVCB_OCPP20.Packet.Messages.IConfirmation)analysisResult.Message as EVCB_OCPP20.Packet.Messages.SetNetworkProfileResponse;
+
+                                                if (response.Status == EVCB_OCPP20.Packet.DataTypes.EnumTypes.SetNetworkProfileStatusEnumType.Accepted)
+                                                {
+                                                    var request = new EVCB_OCPP20.Packet.Messages.SetVariablesRequest()
+                                                    {
+                                                        SetVariableData = new List<EVCB_OCPP20.Packet.DataTypes.SetVariableDataType>()
+                                                         {
+                                                              new EVCB_OCPP20.Packet.DataTypes.SetVariableDataType()
+                                                              {
+                                                                    Component=new EVCB_OCPP20.Packet.DataTypes.ComponentType()
+                                                                    {
+                                                                         Name="OCPPCommCtrlr",
+
+                                                                    },
+                                                                     AttributeType= EVCB_OCPP20.Packet.DataTypes.EnumTypes.AttributeEnumType.Actual,
+                                                                     AttributeValue= JsonConvert.SerializeObject(new List<int>(){ 1 }),
+                                                                     Variable=new EVCB_OCPP20.Packet.DataTypes.VariableType()
+                                                                    {
+                                                                            Name="NetworkConfigurationPriority",
+
+                                                                    }
+
+
+                                                              }
+                                                         }
+
+                                                    };
+                                                    var uuid = session.queue20.store(request);
+                                                    string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "SetVariables", request);
+                                                    Send(session, requestText, "SetVariables");
+                                                }
+
+                                            }
+                                            break;
+                                        case EVCB_OCPP20.Packet.Features.Actions.SetVariables:
+                                            {
+                                                EVCB_OCPP20.Packet.Messages.SetVariablesResponse response = (EVCB_OCPP20.Packet.Messages.IConfirmation)analysisResult.Message as EVCB_OCPP20.Packet.Messages.SetVariablesResponse;
+
+                                                if (response.SetVariableResult[0].AttributeStatus == EVCB_OCPP20.Packet.DataTypes.EnumTypes.SetVariableStatusEnumType.RebootRequired)
+                                                {
+                                                    var request = new EVCB_OCPP20.Packet.Messages.ResetRequest()
+                                                    {
+                                                        Type = EVCB_OCPP20.Packet.DataTypes.EnumTypes.ResetEnumType.OnIdle
+
+                                                    };
+                                                    var uuid = session.queue20.store(request);
+                                                    string requestText = BasicMessageHandler.GenerateRequestofOCPP20(uuid, "Reset", request);
+                                                    Send(session, requestText, "Reset");
+
+                                                }
+                                            }
+                                            break;
+                                        default:
+                                            {
+                                                logger.Error(string.Format("We don't implement messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
+                                            }
+                                            break;
+                                    }
+                                }
+
+                            }
+                            break;
+                        case BasicMessageHandler.TYPENUMBER_CALLERROR:
+                            {
+                                //只處理 丟出Request 收到Error的訊息                              
+                                if (analysisResult.Success && analysisResult.Message != null)
+                                {
+                                    Actions action = Convertor.GetAction(analysisResult.Action);
+                                    ProcessErrorMessage(analysisResult, session, action);
+                                }
+
+                            }
+                            break;
+                        default:
+                            {
+                                logger.Error(string.Format("Can't analyze messagetype:{0} of raw data :{1} by {2}", analysisResult.Id, rawdata, session.ChargeBoxId));
+                            }
+                            break;
+
+                    }
+                }
+
+                await Task.Delay(10);
+            }
+            catch (Exception ex)
+            {
+
+
+                if (ex.InnerException != null)
+                {
+                    logger.Error(string.Format("{0} **Inner Exception :{1} ", session.ChargeBoxId + rawdata, ex.ToString()));
+
+
+                }
+                else
+                {
+                    logger.Error(string.Format("{0} **Exception :{1} ", session.ChargeBoxId, ex.ToString()));
+                }
+            }
+
+
+        }
+
+        async private void ProcessRequestMessage(MessageResult analysisResult, ClientData session, Actions action)
+        {
+            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+            if (!session.IsCheckIn && action != Actions.BootNotification)
+            {
+                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.GenericError, OCPPErrorDescription.NotChecked);
+                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"));
+            }
+            else
+            {
+                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
+                switch (profileName)
+                {
+                    case "Core":
+                        {
+
+                            var replyResult = await profileHandler.ExecuteCoreRequest(action, session, (IRequest)analysisResult.Message).ConfigureAwait(false);
+                            if (replyResult.Success)
+                            {
+                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
+
+
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation"), replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString());
+
+                                if (action == Actions.BootNotification && replyResult.Message is BootNotificationConfirmation)
+                                {
+                                    session.IsCheckIn = true;
+                                    if (((BootNotificationConfirmation)replyResult.Message).status == Packet.Messages.SubTypes.RegistrationStatus.Accepted)
+                                    {
+
+                                        CheckVersion(session.ChargeBoxId);
+                                        CheckEVSEConfigure(session.ChargeBoxId);
+                                        if (session.CustomerId == new Guid("298918C0-6BB5-421A-88CC-4922F918E85E") || session.CustomerId == new Guid("9E6BFDCC-09FB-4DAB-A428-43FE507600A3"))
+                                        {
+                                            using (var db = new MainDBContext())
+                                            {
+                                                db.ServerMessage.Add(new ServerMessage()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    CreatedBy = "Server",
+                                                    CreatedOn = DateTime.UtcNow,
+                                                    OutAction = Actions.ChangeConfiguration.ToString(),
+                                                    OutRequest = JsonConvert.SerializeObject(
+                                                   new ChangeConfigurationRequest()
+                                                   {
+                                                       key = "TimeOffset",
+                                                       value = "+08:00"
+
+                                                   },
+                                                   new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                    SerialNo = Guid.NewGuid().ToString(),
+                                                    InMessage = string.Empty
+
+                                                });
+
+
+                                                db.SaveChanges();
+                                            }
+
+                                        }
+
+
+                                        if (session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8"))
+                                        {
+
+                                            var stationInfo = await GetStationInfo(session.MachineId);
+                                            if (stationInfo != null)
+                                            {
+                                                session.StationLocation = string.Format("{0},{1}", stationInfo.Lat, stationInfo.Long);
+                                                session.StationName = stationInfo.ZipCode;
+                                            }
+                                            using (var db = new MainDBContext())
+                                            {
+                                                db.ServerMessage.Add(new ServerMessage()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    CreatedBy = "Server",
+                                                    CreatedOn = DateTime.UtcNow,
+                                                    OutAction = Actions.DataTransfer.ToString(),
+                                                    OutRequest = JsonConvert.SerializeObject(
+                                                          new DataTransferRequest()
+                                                          {
+                                                              messageId = "ID_Station_Location",
+                                                              vendorId = "Phihong Technology",
+                                                              data = JsonConvert.SerializeObject(new { stationName = session.StationName })
+
+                                                          },
+                                                          new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                    SerialNo = Guid.NewGuid().ToString(),
+                                                    InMessage = string.Empty
+
+                                                });
+
+
+                                                db.ServerMessage.Add(new ServerMessage()
+                                                {
+                                                    ChargeBoxId = session.ChargeBoxId,
+                                                    CreatedBy = "Server",
+                                                    CreatedOn = DateTime.UtcNow,
+                                                    OutAction = Actions.ChangeConfiguration.ToString(),
+                                                    OutRequest = JsonConvert.SerializeObject(
+                                                         new ChangeConfigurationRequest()
+                                                         {
+                                                             key = "TimeOffset",
+                                                             value = "+08:00"
+
+                                                         },
+                                                         new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                    SerialNo = Guid.NewGuid().ToString(),
+                                                    InMessage = string.Empty
+
+                                                });
+
+
+                                                if (!TCCStationDic.ContainsKey(session.StationLocation))
+                                                {
+
+                                                    _CheckWeatherDt = DateTime.UtcNow.AddDays(-1);
+                                                }
+                                                else
+                                                {
+
+                                                    db.ServerMessage.Add(new ServerMessage()
+                                                    {
+                                                        ChargeBoxId = session.ChargeBoxId,
+                                                        CreatedBy = "Server",
+                                                        CreatedOn = DateTime.UtcNow,
+                                                        OutAction = Actions.DataTransfer.ToString(),
+                                                        OutRequest = JsonConvert.SerializeObject(
+                                                        new DataTransferRequest()
+                                                        {
+                                                            messageId = "ID_Weather_Info",
+                                                            vendorId = "Phihong Technology",
+                                                            data = JsonConvert.SerializeObject(
+                                                                new
+                                                                {
+                                                                    weatherId = TCCStationDic[session.StationLocation].WeatherID,
+                                                                    Temperature = TCCStationDic[session.StationLocation].Temperature
+                                                                })
+                                                        },
+                                                        new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                        SerialNo = Guid.NewGuid().ToString(),
+                                                        InMessage = string.Empty
+
+                                                    });
+
+                                                }
+
+                                                db.SaveChanges();
+
+                                            }
+
+                                        }
+                                    }
+                                    else
+                                    {
+                                        using (var db = new MainDBContext())
+                                        {
+                                            var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
+                                            if (machine != null)
+                                            {
+                                                if (machine.ConnectorType.Contains("6") || machine.ConnectorType.Contains("7") || machine.ConnectorType.Contains("8") || machine.ConnectorType.Contains("9"))
+                                                {
+                                                    session.IsAC = false;
+                                                }
+                                                machine.ConnectionType = session.Origin.Contains("https") ? 2 : 1;
+                                                db.SaveChanges();
+                                            }
+                                        }
+
+                                        await SetDefaultFee(session);
+                                    }
+                                }
+
+                                #region 台泥
+                                if (action == Actions.StartTransaction && session.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8") && replyResult.Message is StartTransactionConfirmation)
+                                {
+
+                                    StartTransactionConfirmation confirm = (StartTransactionConfirmation)replyResult.Message;
+                                    StartTransactionRequest request = (StartTransactionRequest)analysisResult.Message;
+                                    using (var db = new MainDBContext())
+                                    {
+                                        db.ServerMessage.Add(new ServerMessage()
+                                        {
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            CreatedBy = "Server",
+                                            CreatedOn = DateTime.UtcNow,
+                                            OutAction = Actions.DataTransfer.ToString(),
+                                            OutRequest = JsonConvert.SerializeObject(
+                                                    new DataTransferRequest()
+                                                    {
+                                                        messageId = "ID_GetTxUserInfo",
+                                                        vendorId = "Phihong Technology",
+                                                        data = JsonConvert.SerializeObject(new { txId = confirm.transactionId, ConnectorId = request.connectorId })
+                                                    },
+                                                    new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                            SerialNo = Guid.NewGuid().ToString(),
+                                            InMessage = string.Empty
+
+                                        });
+
+                                        db.SaveChanges();
+                                    }
+                                }
+                                #endregion
+
+                                if (action == Actions.Authorize && replyResult.Message is AuthorizeConfirmation)
+                                {
+                                    var authorizeRequest = (IRequest)analysisResult.Message as AuthorizeRequest;
+                                    if (session.UserDisplayPrices.ContainsKey(authorizeRequest.idTag))
+                                    {
+                                        using (var db = new MainDBContext())
+                                        {
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.DataTransfer.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                           new DataTransferRequest()
+                                                           {
+                                                               messageId = "SetUserPrice",
+                                                               vendorId = "Phihong Technology",
+                                                               data = JsonConvert.SerializeObject(
+                                                                   new
+                                                                   {
+                                                                       idToken = authorizeRequest.idTag,
+                                                                       price = session.UserDisplayPrices[authorizeRequest.idTag]
+
+                                                                   })
+                                                           },
+                                                           new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            });
+
+                                            db.SaveChanges();
+                                        }
+                                    }
+                                }
+
+                            }
+                            else
+                            {
+                                if (action == Actions.StopTransaction && replyResult.CallErrorMsg == "Reject Response Message")
+                                {
+                                    //do nothing 
+                                }
+                                else
+                                {
+                                    string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                                    string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;
+
+                                    Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                                }
+                            }
+
+                            if (action == Actions.StartTransaction)
+                            {
+                                var stationId = _loadingBalanceService.GetStationIdByMachineId(session.MachineId);
+                                var _powerDic = _loadingBalanceService.GetSettingPower(stationId, session.MachineId);
+                                if (_powerDic != null)
+                                {
+                                    foreach (var kv in _powerDic)
+                                    {
+                                        try
+                                        {
+                                            string chargeBoxId = string.Empty;
+                                            //set profile
+                                            lock (_lockClientDic)
+                                            {
+                                                chargeBoxId = clientDic.Where(x => x.Value.MachineId == kv.Key).Select(x => x.Value.ChargeBoxId).FirstOrDefault();
+                                            }
+
+                                            if (chargeBoxId != null && kv.Value.HasValue)
+                                            {
+                                                profileHandler.SetChargingProfile(chargeBoxId, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W);
+                                            }
+                                        }
+                                        catch (Exception ex)
+                                        {
+                                            logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString()));
+                                        }
+
+                                    }
+                                }
+                            }
+
+                            if (action == Actions.StopTransaction)
+                            {
+                                var stationId = _loadingBalanceService.GetStationIdByMachineId(session.MachineId);
+                                if (_loadingBalanceService.IsNeedtoCancelSetting(stationId, session.MachineId, session.ChargeBoxId))
+                                {
+                                    //Clear  current profile    
+                                    profileHandler.ClearChargingProfile(session.ChargeBoxId);
+
+                                    var _powerDic = _loadingBalanceService.GetRerangeSettingPower(stationId);
+                                    if (_powerDic != null)
+                                    {
+                                        foreach (var kv in _powerDic)
+                                        {
+                                            try
+                                            {
+                                                string chargeBoxId = string.Empty;
+                                                //set profile
+                                                lock (_lockClientDic)
+                                                {
+                                                    chargeBoxId = clientDic.Where(x => x.Value.MachineId == kv.Key).Select(x => x.Value.ChargeBoxId).FirstOrDefault();
+                                                }
+
+                                                if (chargeBoxId != null && kv.Value.HasValue)
+                                                {
+                                                    profileHandler.SetChargingProfile(chargeBoxId, kv.Value.Value, Packet.Messages.SubTypes.ChargingRateUnitType.W);
+                                                }
+                                            }
+                                            catch (Exception ex)
+                                            {
+                                                logger.Error(string.Format("Set Profile Exception: {0}", ex.ToString()));
+                                            }
+
+                                        }
+                                    }
+
+                                }
+
+                            }
+
+                        }
+                        break;
+                    case "FirmwareManagement":
+                        {
+                            var replyResult = profileHandler.ExecuteFirmwareManagementRequest(action, session, (IRequest)analysisResult.Message);
+                            if (replyResult.Success)
+                            {
+                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation", replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString()));
+
+                            }
+                            else
+                            {
+                                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                                string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;
+
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                            }
+
+                        }
+                        break;
+                    case "Security":
+                        {
+                            var replyResult = profileHandler.ExecuteSecurityRequest(action, session, (IRequest)analysisResult.Message);
+                            if (replyResult.Success)
+                            {
+                                string response = BasicMessageHandler.GenerateConfirmation(analysisResult.UUID, (IConfirmation)replyResult.Message);
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Confirmation", replyResult.Exception == null ? string.Empty : replyResult.Exception.ToString()));
+
+                            }
+                            else
+                            {
+                                string response = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                                string errorMsg = replyResult.Exception != null ? replyResult.Exception.ToString() : string.Empty;
+
+                                Send(session, response, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                            }
+                        }
+                        break;
+                    default:
+                        {
+                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
+                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                        }
+                        break;
+
+                }
+            }
+        }
+
+        async private void ProcessConfirmationMessage(MessageResult analysisResult, ClientData session, Actions action)
+        {
+
+            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+            if (ReConfirmMessage(analysisResult))
+            {
+                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
+                MessageResult confirmResult = null;
+                switch (profileName)
+                {
+                    case "Core":
+                        {
+                            confirmResult = await profileHandler.ExecuteCoreConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "FirmwareManagement":
+                        {
+                            confirmResult = profileHandler.ExecuteFirmwareManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "RemoteTrigger":
+                        {
+                            confirmResult = profileHandler.ExecuteRemoteTriggerConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "Reservation":
+                        {
+                            confirmResult = profileHandler.ExecuteReservationConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "LocalAuthListManagement":
+                        {
+                            confirmResult = profileHandler.ExecuteLocalAuthListManagementConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "SmartCharging":
+                        {
+                            confirmResult = profileHandler.ExecuteSmartChargingConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    case "Security":
+                        {
+                            confirmResult = profileHandler.ExecuteSecurityConfirm(action, session, (IConfirmation)analysisResult.Message, analysisResult.RequestId);
+                        }
+                        break;
+                    default:
+                        {
+                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
+                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                        }
+                        break;
+
+                }
+
+                if (confirmResult == null || !confirmResult.Success)
+                {
+                    logger.Error(string.Format("Action:{0} MessageId:{1}  ExecuteConfirm Error:{2} ",
+                        analysisResult.Action, analysisResult.UUID, confirmResult.Exception.ToString()));
+                }
+            }
+            else
+            {
+                string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                string errorMsg = string.Format("Action:{0} MessageId:{1}  didn't exist in confirm message", analysisResult.Action, analysisResult.UUID);
+                Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+            }
+        }
+
+        private void ProcessErrorMessage(MessageResult analysisResult, ClientData session, Actions action)
+        {
+            BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+            if (ReConfirmMessage(analysisResult))
+            {
+                var profileName = profiles.Where(x => x.IsExisted(analysisResult.Action)).Select(x => x.Name).FirstOrDefault();
+                switch (profileName)
+                {
+                    case "Core":
+                        {
+                            profileHandler.ReceivedCoreError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "FirmwareManagement":
+                        {
+                            profileHandler.ReceivedFirmwareManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "RemoteTrigger":
+                        {
+                            profileHandler.ReceivedRemoteTriggerError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "Reservation":
+                        {
+                            profileHandler.ExecuteReservationError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "LocalAuthListManagement":
+                        {
+                            profileHandler.ReceivedLocalAuthListManagementError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    case "SmartCharging":
+                        {
+                            profileHandler.ReceivedSmartChargingError(action, analysisResult.ReceivedErrorCode, session, analysisResult.RequestId);
+                        }
+                        break;
+                    default:
+                        {
+                            string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                            string errorMsg = string.Format("Couldn't find action name: {0} of profile", action);
+                            Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+                        }
+                        break;
+
+                }
+            }
+            else
+            {
+                string replyMsg = BasicMessageHandler.GenerateCallError(analysisResult.UUID, OCPPErrorCodes.InternalError, OCPPErrorDescription.InternalError);
+                string errorMsg = string.Format("Action:{0} MessageId:{1}  didn't exist in confirm message", analysisResult.Action, analysisResult.UUID);
+                Send(session, replyMsg, string.Format("{0} {1}", analysisResult.Action, "Error"), errorMsg);
+
+
+            }
+        }
+
+
+        private void Send(ClientData session, string msg, string messageType, string errorMsg = "")
+        {
+            try
+            {
+
+                if (session != null)
+                {
+                    WriteMachineLog(session, msg, messageType, errorMsg, true);
+                    session.Send(msg);
+                }
+
+            }
+            catch (Exception ex)
+            {
+                logger.Error(string.Format("Send Ex:{0}", ex.ToString()));
+            }
+
+
+        }
+
+        async private void ServerUpdateTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                var min_Interval = (DateTime.UtcNow - checkUpdateDt).TotalMinutes;
+                if (min_Interval > 3)
+                {
+                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                    Dictionary<string, ClientData> _copyClientDic = null;
+                    lock (_lockClientDic)
+                    {
+                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                    }
+                    checkUpdateDt = DateTime.UtcNow;
+                    using (var db = new MainDBContext())
+                    {
+                        //var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
+                        //    x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
+                        //    .Select(x => new { x.Id, x.ChargeBoxId, x.FW_AssignedMachineVersionId }).ToList();
+
+                        var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true &&
+                          x.FW_AssignedVersion != x.FW_VersionReport && x.Online == true)
+                          .Select(x => x.ChargeBoxId).AsNoTracking().ToList();
+
+                        foreach (var chargeBoxId in needUpdateChargers)
+                        {
+                            try
+                            {
+
+
+                                ClientData session;
+                                if (_copyClientDic.TryGetValue(chargeBoxId, out session))
+                                {
+
+                                    string requestId = Guid.NewGuid().ToString();
+                                    // using (var db = new MainDBContext())
+
+                                    if (session.IsCheckIn && !session.ISOCPP20)
+                                    {
+
+                                        var _request = new TriggerMessageRequest()
+                                        {
+                                            requestedMessage = Packet.Messages.SubTypes.MessageTrigger.FirmwareStatusNotification
+                                        };
+
+                                        var uuid = session.queue.store(_request);
+                                        string rawRequest = BasicMessageHandler.GenerateRequest(uuid, _request.Action, _request);
+                                        Send(session, rawRequest, string.Format("{0} {1}", _request.Action, "Request"), "");
+
+                                        #region OCTT   ,測試韌體更新方式
+                                        //--------------------> OCTT   ,測試韌體更新方式
+                                        //{
+                                        //    var machine = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
+                                        //        x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
+                                        //        .Select(x => new { x.Id, x.FW_AssignedMachineVersionId }).FirstOrDefault();
+
+                                        //    if (machine != null)
+                                        //    {
+                                        //        var mv = db.MachineVersion.Include(c => c.PublishVersion)
+                                        //         .Include(c => c.PublishVersion.PublishVersionFiles)
+                                        //         .Include(c => c.PublishVersion.PublishVersionFiles.Select(z => z.UploadFile))
+                                        //         .Where(c => c.Id == machine.FW_AssignedMachineVersionId.Value).First();
+
+                                        //        string downloadUrl = mv.PublishVersion.PublishVersionFiles.FirstOrDefault().UploadFile.FileUrl;
+
+                                        //        var _updateFWrequest = new UpdateFirmwareRequest()
+                                        //        {
+                                        //            location = new Uri(downloadUrl),
+                                        //            retries = 3,
+                                        //            retrieveDate = DateTime.UtcNow,
+                                        //            retryInterval = 10
+                                        //        };
+                                        //        db.MachineOperateRecord.Add(new MachineOperateRecord()
+                                        //        {
+                                        //            CreatedOn = DateTime.UtcNow,
+                                        //            ChargeBoxId = session.ChargeBoxId,
+                                        //            SerialNo = requestId,
+                                        //            RequestContent = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                        //            EVSE_Status = 0,
+                                        //            EVSE_Value = "Fw Version:" + machine.FW_AssignedMachineVersionId,
+                                        //            Status = 0,
+                                        //            RequestType = 0,
+
+                                        //        });
+
+                                        //        db.ServerMessage.Add(new ServerMessage()
+                                        //        {
+                                        //            ChargeBoxId = session.ChargeBoxId,
+                                        //            CreatedBy = "Server",
+                                        //            CreatedOn = DateTime.UtcNow,
+                                        //            OutAction = _updateFWrequest.Action.ToString(),
+                                        //            OutRequest = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                        //            SerialNo = requestId,
+                                        //            InMessage = string.Empty
+
+                                        //        });
+
+                                        //        db.SaveChanges();
+
+                                        //    }
+
+                                        //}
+                                        #endregion
+                                    }
+
+
+
+                                }
+
+
+                            }
+                            catch (Exception ex)
+                            {
+                                logger.Error(string.Format("serverUpdateTrigger ChargeBoxId:{0}  Ex:{1}", chargeBoxId, ex.ToString()));
+                            }
+                        }
+                    }
+                    await Task.Delay(1000);
+                    //  Thread.CurrentThread.Join(1000);
+                }
+            }
+        }
+        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+
+        async private void ServerMessageTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                try
+                {
+                    RemoveConfirmMessage();
+
+                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                    using (var db = new MainDBContext())
+                    {
+                        DateTime startDt = DateTime.UtcNow.AddSeconds(-30);
+                        DateTime dt = new DateTime(1991, 1, 1);
+                        DateTime currentTime = DateTime.UtcNow;
+                        var commandList = db.ServerMessage.Where(c => c.ReceivedOn == dt && c.UpdatedOn == dt && c.CreatedOn >= startDt && c.CreatedOn <= currentTime).AsNoTracking().ToList();
+
+
+                        //處理主機傳送的有指令
+                        var cmdMachineList = commandList.Select(c => c.ChargeBoxId).Distinct().ToList();
+                        if (commandList.Count > 0)
+                        {
+                            // Console.WriteLine(string.Format("Now:{0} commandList Count:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), commandList.Count));
+                        }
+                        var resendList = GetResendMessage();
+                        foreach (var resendItem in resendList)
+                        {
+                            ClientData session;
+                            if (clientDic.TryGetValue(resendItem.ChargePointSerialNumber, out session))
+                            {
+                                if (DateTime.UtcNow.Subtract(resendItem.SentOn).TotalSeconds > 1)
+                                {
+                                    resendItem.SentTimes--;
+                                    resendItem.SentOn = DateTime.UtcNow;
+                                    Send(session, resendItem.SentMessage, string.Format("{0} {1}", resendItem.SentAction, "Request"), "");
+                                }
+
+                            }
+
+                        }
+                        foreach (var charger_SN in cmdMachineList)
+                        {
+                            ClientData session;
+                            string uuid = string.Empty;
+                            if (clientDic.TryGetValue(charger_SN, out session))
+                            {
+                                //logger.Debug(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss")));
+
+                                if (session.IsCheckIn && !session.ISOCPP20)
+                                {
+                                    string rawRequest = string.Empty;
+
+                                    var cmdList = commandList.Where(c => c.ChargeBoxId == charger_SN).ToList();
+
+                                    foreach (var item in cmdList)
+                                    {
+                                        IRequest request = null;
+                                        Actions action = Actions.None;
+                                        Enum.TryParse(item.OutAction, out action);
+                                        Type _RequestType = null;
+
+                                        for (int i = 0; i < profiles.Count; i++)
+                                        {
+                                            var feature = profiles[i].GetFeaturebyAction(item.OutAction);
+
+                                            if (feature != null)
+                                            {
+                                                _RequestType = feature.GetRequestType();
+                                                break;
+                                            }
+                                        }
+
+                                        if (_RequestType != null && item.CreatedBy != "Destroyer")
+                                        {
+                                            request = JsonConvert.DeserializeObject(item.OutRequest, _RequestType) as IRequest;
+                                            uuid = session.queue.store(request);
+                                            rawRequest = BasicMessageHandler.GenerateRequest(uuid, item.OutAction, request);
+                                            Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");
+                                        }
+
+
+                                        if (item.CreatedBy == "Destroyer")
+                                        {
+
+                                            if (_RequestType != null)
+                                            {
+                                                request = Activator.CreateInstance(_RequestType) as IRequest;
+                                                uuid = session.queue.store(request);
+                                                rawRequest = BasicMessageHandler.GenerateDestroyRequest(uuid, item.OutAction, item.OutRequest);
+                                                Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");
+
+                                            }
+                                            else
+                                            {
+
+                                                rawRequest = BasicMessageHandler.GenerateDestroyRequest(Guid.NewGuid().ToString(), item.OutAction, item.OutRequest);
+                                                Send(session, rawRequest, string.Format("{0} {1}", action, "Request"), "");
+
+                                            }
+                                        }
+
+                                        AddConfirmMessage(charger_SN, item.Id, item.SerialNo, item.OutAction, uuid, item.CreatedBy, rawRequest);
+
+                                        #region 更新資料表單一欄位
+                                        var _UpdatedItem = new ServerMessage() { Id = item.Id, UpdatedOn = DateTime.UtcNow };
+                                        db.Configuration.AutoDetectChangesEnabled = false;//自動呼叫DetectChanges()比對所有的entry集合的每一個屬性Properties的新舊值
+                                        db.Configuration.ValidateOnSaveEnabled = false;// 因為Entity有些欄位必填,若不避開會有Validate錯誤
+                                                                                       // var _UpdatedItem = db.ServerMessage.Where(x => x.Id == item.Id).FirstOrDefault();
+                                        db.ServerMessage.Attach(_UpdatedItem);
+                                        _UpdatedItem.UpdatedOn = DateTime.UtcNow;
+                                        db.Entry(_UpdatedItem).Property(x => x.UpdatedOn).IsModified = true;// 可以直接使用這方式強制某欄位要更新,只是查詢集合耗效能而己
+
+                                        db.SaveChanges();
+
+                                        #endregion
+
+                                        await Task.Delay(100);
+
+                                    }
+
+                                }
+                            }
+                        }
+
+                    }
+
+                    await Task.Delay(500);
+
+                }
+                catch (Exception ex)
+                {
+                    logger.Error(string.Format("ServerMessageTrigger  Ex:{0}", ex.ToString()));
+                }
+            }
+        }
+
+
+        async private void HeartBeatCheckTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                try
+                {
+                    if (DateTime.UtcNow.Subtract(lastcheckdt).TotalSeconds > 30)
+                    {
+                        lastcheckdt = DateTime.UtcNow;
+                        Stopwatch watch = new Stopwatch();
+                        Dictionary<string, ClientData> _copyClientDic = null;
+                        lock (_lockClientDic)
+                        {
+                            _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+                        }
+
+                        var cdt = DateTime.UtcNow;
+                        var clients = _copyClientDic.Where(x => x.Value.LastActiveTime > cdt.AddSeconds(-120)).Select(x => x.Value).ToList();
+
+                        watch.Start();
+                        foreach (var session in clients)
+                        {
+                            using (var db = new MainDBContext())
+                            {
+                                var machine = new Machine() { Id = session.MachineId };
+                                if (machine != null)
+                                {
+                                    db.Configuration.AutoDetectChangesEnabled = false;
+                                    db.Configuration.ValidateOnSaveEnabled = false;
+                                    db.Machine.Attach(machine);
+                                    machine.HeartbeatUpdatedOn = DateTime.UtcNow;
+                                    machine.ConnectionType = session.UriScheme.Equals("wss") ? 2 : 1;
+                                    db.Entry(machine).Property(x => x.HeartbeatUpdatedOn).IsModified = true;
+                                    db.Entry(machine).Property(x => x.ConnectionType).IsModified = true;
+                                    await db.SaveChangesAsync();
+                                }
+
+                            }
+                        }
+                        watch.Stop();
+                        if (watch.ElapsedMilliseconds / 1000 > 5)
+                        {
+                            logger.Fatal("Update HeartBeatCheckTrigger cost " + watch.ElapsedMilliseconds / 1000 + " seconds.");
+                        }
+                    }
+
+
+                    await Task.Delay(10000);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("***********************************************************");
+                    logger.Error(string.Format("HeartBeatCheckTrigger  Ex:{0}", ex.ToString()));
+                }
+
+            }
+        }
+
+        async private void ServerWeatherNotificationTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                var min_Interval = (DateTime.UtcNow - _CheckWeatherDt).TotalMinutes;
+
+                if (min_Interval > 30)
+                {
+                    // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
+                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                    Dictionary<string, ClientData> _copyClientDic = null;
+                    lock (_lockClientDic)
+                    {
+                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                    }
+                    _CheckWeatherDt = DateTime.UtcNow;
+
+                    var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
+
+                    // Console.WriteLine("in...............ServerWeatherNotificationTrigger");
+                    foreach (var location in locations)
+                    {
+
+                        try
+                        {   //query weather
+                            var httpResult = await httpClient.GetWeather("https://api.weatherapi.com/v1/current.json?key=874346abc0874e69a9423510222201&q=" + location, null, null);
+
+                            string temp = "17";
+                            string weather_code = "1183";
+                            if (httpResult.Status == System.Net.HttpStatusCode.OK)
+                            {
+                                try
+                                {
+                                    var jsonResult = JsonConvert.DeserializeObject(httpResult.Response) as JObject;
+                                    temp = jsonResult["current"]["temp_c"].ToString();
+                                    weather_code = jsonResult["current"]["condition"]["code"].ToString();
+
+
+                                }
+                                catch (Exception ex)
+                                {
+                                    ;
+                                }
+
+                            }
+
+                            #region 台泥氣象Mapping
+                            switch (weather_code)
+                            {
+                                case "1000":
+                                    weather_code = "1";
+                                    break;
+                                case "1003":
+                                case "1006":
+                                case "1009":
+                                    weather_code = "2";
+                                    break;
+                                case "1063":
+                                case "1072":
+                                case "1150":
+                                case "1153":
+                                case "1168":
+                                case "1171":
+                                case "1180":
+                                case "1183":
+                                case "1186":
+                                case "1189":
+                                case "1192":
+                                case "1195":
+                                case "1198":
+                                case "1201":
+                                case "1237":
+                                case "1240":
+                                case "1243":
+                                case "1246":
+                                case "1261":
+                                case "1264":
+                                    weather_code = "3";
+                                    break;
+                                case "1087":
+                                case "1273":
+                                case "1276":
+                                case "1279":
+                                case "1282":
+                                    weather_code = "4";
+                                    break;
+                                case "1066":
+                                case "1069":
+                                case "1114":
+                                case "1117":
+                                case "1204":
+                                case "1207":
+                                case "1210":
+                                case "1213":
+                                case "1216":
+                                case "1219":
+                                case "1222":
+                                case "1225":
+                                case "1249":
+                                case "1252":
+                                case "1255":
+                                case "1258":
+                                    weather_code = "5";
+                                    break;
+                                case "1030":
+                                case "1135":
+                                case "1147":
+                                    weather_code = "2";
+                                    break;
+                                default:
+                                    weather_code = "2";
+                                    break;
+                            }
+                            #endregion
+
+
+                            if (TCCStationDic.ContainsKey(location))
+                            {
+                                TCCStationDic[location].Temperature = (int)double.Parse(temp);
+                                TCCStationDic[location].WeatherID = int.Parse(weather_code);
+                            }
+                            else
+                            {
+                                TCCStationDic.Add(location, new TCCWeatherDto() { WeatherID = int.Parse(weather_code), Temperature = (int)double.Parse(temp) });
+                            }
+
+                        }
+                        catch (Exception ex)
+                        {
+                            logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0}  Ex:{1}", location, ex.ToString()));
+                        }
+                    }
+
+                    var clients = _copyClientDic.Where(x => x.Value.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).
+                    Select(x => new { ChargeBoxId = x.Value.ChargeBoxId, StationLocation = x.Value.StationLocation }).ToList();
+
+                    using (var db = new MainDBContext())
+                    {
+
+                        foreach (var client in clients)
+                        {
+                            try
+                            {
+                                if (string.IsNullOrEmpty(client.StationLocation))
+                                {
+                                    Console.WriteLine(client.StationLocation + " is empty");
+                                    continue;
+                                }
+
+
+                                if (TCCStationDic.ContainsKey(client.StationLocation))
+                                {
+                                    db.ServerMessage.Add(new ServerMessage()
+                                    {
+                                        ChargeBoxId = client.ChargeBoxId,
+                                        CreatedBy = "Server",
+                                        CreatedOn = DateTime.UtcNow,
+                                        OutAction = Actions.DataTransfer.ToString(),
+                                        OutRequest = JsonConvert.SerializeObject(
+                                                           new DataTransferRequest()
+                                                           {
+                                                               messageId = "ID_Weather_Info",
+                                                               vendorId = "Phihong Technology",
+                                                               data = JsonConvert.SerializeObject(
+                                                                   new
+                                                                   {
+                                                                       weatherId = TCCStationDic[client.StationLocation].WeatherID,
+                                                                       Temperature = TCCStationDic[client.StationLocation].Temperature
+                                                                   })
+                                                           },
+                                                           new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                        SerialNo = Guid.NewGuid().ToString(),
+                                        InMessage = string.Empty
+
+                                    });
+
+                                    await db.SaveChangesAsync();
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                logger.Error(string.Format("ServerWeatherNotificationTrigger ChargeBoxId:{0}  Ex:{1}", client.ChargeBoxId, ex.ToString()));
+                            }
+
+
+                        }
+                    }
+
+                }
+                await Task.Delay(1000);
+            }
+        }
+
+        async private void ServerSetFeeTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                var min_Interval = (DateTime.UtcNow - _CheckFeeDt).TotalMinutes;
+                if (min_Interval > 1)
+                {
+                    BasicMessageHandler msgAnalyser = new BasicMessageHandler();
+                    Dictionary<string, ClientData> _copyClientDic = null;
+                    lock (_lockClientDic)
+                    {
+                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                    }
+                    _CheckFeeDt = DateTime.UtcNow;
+                    foreach (var item in _copyClientDic)
+                    {
+                        try
+                        {
+                            ClientData session = item.Value;
+                            if (session.IsCheckIn)
+                            {
+
+                                string displayPriceText = await SetDefaultFee(session);
+                                if (!string.IsNullOrEmpty(displayPriceText) && displayPriceText != session.DisplayPrice)
+                                {
+                                    clientDic[item.Key].DisplayPrice = displayPriceText;
+
+                                    using (var db = new MainDBContext())
+                                    {
+                                        db.ServerMessage.Add(new ServerMessage()
+                                        {
+                                            ChargeBoxId = session.ChargeBoxId,
+                                            CreatedBy = "Server",
+                                            CreatedOn = DateTime.UtcNow,
+                                            OutAction = Actions.ChangeConfiguration.ToString(),
+                                            OutRequest = JsonConvert.SerializeObject(
+                                                    new ChangeConfigurationRequest()
+                                                    {
+                                                        key = "DefaultPrice",
+                                                        value = clientDic[item.Key].DisplayPrice
+                                                    },
+                                                    new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                            SerialNo = Guid.NewGuid().ToString(),
+                                            InMessage = string.Empty
+
+                                        }); ;
+
+                                        if (session.CustomerId == new Guid("10C7F5BD-C89A-4E2A-8611-B617E0B41A73"))
+                                        {
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.ChangeConfiguration.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                   new ChangeConfigurationRequest()
+                                                   {
+                                                       key = "ConnectionTimeOut",
+                                                       value = "120"
+                                                   },
+                                                   new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            });
+                                            db.ServerMessage.Add(new ServerMessage()
+                                            {
+                                                ChargeBoxId = session.ChargeBoxId,
+                                                CreatedBy = "Server",
+                                                CreatedOn = DateTime.UtcNow,
+                                                OutAction = Actions.ChangeConfiguration.ToString(),
+                                                OutRequest = JsonConvert.SerializeObject(
+                                                   new ChangeConfigurationRequest()
+                                                   {
+                                                       key = "MeterValueSampleInterval",
+                                                       value = "3"
+                                                   },
+                                                   new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
+                                                SerialNo = Guid.NewGuid().ToString(),
+                                                InMessage = string.Empty
+
+                                            });
+                                        }
+
+                                        await db.SaveChangesAsync();
+
+                                    }
+                                }
+                            }
+
+                        }
+                        catch (Exception ex)
+                        {
+                            logger.Error(string.Format("ServerSetFeeTrigger ChargeBoxId:{0}  Ex:{1}", item.Key, ex.ToString()));
+                        }
+                    }
+                }
+                await Task.Delay(1000);
+            }
+        }
+
+        async private Task<string> SetDefaultFee(ClientData client)
+        {
+            string displayPriceText = string.Empty;
+            string charingPriceText = string.Empty;
+
+            if (string.IsNullOrEmpty(client.ChargeBoxId)) return displayPriceText;
+
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@MachineId", client.MachineId, DbType.String, ParameterDirection.Input);
+                string displayPricestrSql = "";
+                string strSql = "";
+
+                if (client.IsAC)
+                {
+                    displayPricestrSql = "   SELECT  [AC_BillingMethod] as BillingMethod,[AC_FeeName] as FeeName,[AC_Fee] as ChargingFeebyHour" +
+                "  ,[AC_ParkingFee] as ParkingFee, [Currency]  FROM[StationMachine]  left join[dbo].[Station]" +
+                "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId and Station.IsBilling=1; ";
+
+                    strSql = " SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee]  FROM[StationMachine]  left join [dbo].[StationFee]" +
+                   " on[StationMachine].StationId = StationFee.StationId  where StationMachine.MachineId =@MachineId and StationFee.IsAC=1; ";
+                }
+                else
+                {
+                    displayPricestrSql = "   SELECT  [DC_BillingMethod] as BillingMethod,[DC_FeeName] as FeeName,[DC_Fee] as ChargingFeebyHour" +
+               "  ,[DC_ParkingFee] as ParkingFee, [Currency]  FROM[StationMachine]  left join[dbo].[Station]" +
+               "  on[StationMachine].StationId = Station.[Id]  where StationMachine.MachineId=@MachineId and Station.IsBilling=1; ";
+
+                    strSql = " SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee]  FROM[StationMachine]  left join [dbo].[StationFee]" +
+                   " on[StationMachine].StationId = StationFee.StationId  where StationMachine.MachineId =@MachineId and StationFee.IsAC=0; ";
+
+                }
+                var result = await conn.QueryAsync<StationFee>(displayPricestrSql, parameters);
+                if (result.Count() == 0)
+                {
+                    return string.Empty;
+                }
+                var stationPrice = result.First();
+
+                if (stationPrice.BillingMethod == 1)
+                {
+                    var chargingPriceResult = await conn.QueryAsync<ChargingPrice>(strSql, parameters);
+                    client.ChargingPrices = chargingPriceResult.ToList();
+                    if (string.IsNullOrEmpty(client.ChargingPrices[0].StartTime))
+                    {
+                        client.ChargingPrices = new List<ChargingPrice>();
+                    }
+                }
+
+                displayPriceText = stationPrice.FeeName;
+                client.BillingMethod = stationPrice.BillingMethod;
+                client.Currency = stationPrice.Currency;
+                client.ChargingFeebyHour = stationPrice.ChargingFeebyHour;
+                client.ParkingFee = stationPrice.ParkingFee;
+                client.IsBilling = true;
+            }
+
+            return displayPriceText;
+        }
+
+        async private void HealthCheckTrigger()
+        {
+            for (; ; )
+            {
+                if (_ct.IsCancellationRequested)
+                {
+                    break;
+                }
+
+                try
+                {
+                    Dictionary<string, ClientData> _copyClientDic = null;
+                    lock (_lockClientDic)
+                    {
+                        _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+                    }
+
+                    var removeClients = _copyClientDic.Where(x => x.Value.LastActiveTime < DateTime.UtcNow.AddSeconds(-300)).Select(x => x.Value).ToList();
+
+                    foreach (var session in removeClients)
+                    {
+
+                        Console.WriteLine(string.Format("Server forced to shut down ChargeBox ({0}: LastActiveTime{1})", session.ChargeBoxId, session.LastActiveTime));
+                        RemoveClient(session);
+                    }
+
+                    await Task.Delay(60000);
+                }
+                catch (Exception ex)
+                {
+                    logger.Error(string.Format("HealthAlarmTrigger  Ex:{0}", ex.ToString()));
+                }
+
+            }
+        }
+
+
+        private List<NeedConfirmMessage> GetResendMessage()
+        {
+            List<NeedConfirmMessage> sendMessages = new List<NeedConfirmMessage>();
+            lock (_lockConfirmPacketList)
+            {
+                sendMessages = needConfirmPacketList.Where(x => x.SentTimes > 1 && x.CreatedBy == "Server").ToList();
+
+            }
+
+            return sendMessages;
+        }
+
+        private void AddConfirmMessage(string chargePointSerialNumber, int table_id, string requestId, string action, string msg_id, string createdBy, string sendMessage)
+        {
+            NeedConfirmMessage _needConfirmMsg = new NeedConfirmMessage();
+            _needConfirmMsg.Id = table_id;
+            _needConfirmMsg.SentAction = action;
+            _needConfirmMsg.SentOn = DateTime.UtcNow;
+            _needConfirmMsg.SentTimes = 4;
+            _needConfirmMsg.ChargePointSerialNumber = chargePointSerialNumber;
+            _needConfirmMsg.RequestId = requestId;
+            _needConfirmMsg.SentUniqueId = msg_id;
+            _needConfirmMsg.CreatedBy = createdBy;
+            _needConfirmMsg.SentMessage = sendMessage;
+
+            if (needConfirmActions.Contains(action))
+            {
+
+                lock (_lockConfirmPacketList)
+                {
+                    needConfirmPacketList.Add(_needConfirmMsg);
+                }
+            }
+        }
+
+        private void RemoveConfirmMessage()
+        {
+            var before10Mins = DateTime.UtcNow.AddMinutes(-10);
+            lock (_lockConfirmPacketList)
+            {
+                var removeList = needConfirmPacketList.Where(x => x.SentTimes == 0 || x.SentOn < before10Mins).ToList();
+                foreach (var item in removeList)
+                {
+                    needConfirmPacketList.Remove(item);
+                }
+            }
+        }
+
+        private bool ReConfirmMessage(MessageResult analysisResult)
+        {
+            bool confirmed = false;
+            if (needConfirmActions.Contains(analysisResult.Action))
+            {
+
+                NeedConfirmMessage foundRequest = null;
+                lock (_lockConfirmPacketList)
+                {
+                    foundRequest = needConfirmPacketList.Where(x => x.SentUniqueId == analysisResult.UUID).FirstOrDefault();
+                }
+
+                if (foundRequest != null && foundRequest.Id > 0)
+                {
+                    foundRequest.SentTimes = 0;
+                    foundRequest.SentInterval = 0;
+                    analysisResult.RequestId = foundRequest.RequestId;
+
+                    using (var db = new MainDBContext())
+                    {
+                        var sc = db.ServerMessage.Where(x => x.Id == foundRequest.Id).FirstOrDefault();
+                        sc.InMessage = JsonConvert.SerializeObject(analysisResult.Message, Formatting.None);
+                        sc.ReceivedOn = DateTime.UtcNow;
+                        db.SaveChanges();
+                        //  Console.WriteLine(string.Format("Now:{0} ServerMessage Id:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), foundRequest.Id));
+
+                    }
+                    confirmed = true;
+
+
+
+                }
+                else if (analysisResult.Action == Actions.TriggerMessage.ToString())
+                {
+                    confirmed = true;
+                }
+                else
+                {
+                    logger.Error(string.Format("Received no record Action:{0} MessageId:{1} ", analysisResult.Action, analysisResult.UUID));
+                }
+            }
+
+            return confirmed;
+        }
+
+
+
+
+        private void RemoveClient(ClientData session)
+        {
+
+
+            if (session != null)
+            {
+
+                if (!string.IsNullOrEmpty(session.MachineId))
+                    logger.Trace("RemoveClient[" + session.ChargeBoxId + "]");
+
+                if (session.Connected)
+                {
+                    session.Close(CloseReason.ServerShutdown);
+                }
+                RemoveClientDic(session);
+                try
+                {
+                    session.m_ReceiveData -= new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
+                    // session.Close(CloseReason.ServerShutdown);
+
+                }
+                catch (Exception ex)
+                {
+                    //logger.Warn("Close client socket error!!");
+                    logger.Warn(string.Format("Close client socket error!! {0} Msg:{1}", session.ChargeBoxId, ex.Message));
+                }
+
+                if (session != null)
+                {
+                    session = null;
+                }
+
+            }
+        }
+
+        private void RemoveClientDic(ClientData session)
+        {
+            if (!string.IsNullOrEmpty(session.ChargeBoxId))
+            {
+                lock (_lockClientDic)
+                {
+
+                    if (clientDic.ContainsKey(session.ChargeBoxId))
+                    {
+                        if (clientDic[session.ChargeBoxId].SessionID == session.SessionID)
+                        {
+                            logger.Debug(String.Format("ChargeBoxId:{0} Remove SessionId:{1} Removed SessionId:{2}", session.ChargeBoxId, session.SessionID, clientDic[session.ChargeBoxId].SessionID));
+
+                            clientDic.Remove(session.ChargeBoxId);
+                            logger.Trace("RemoveClient ContainsKey " + session.ChargeBoxId);
+                        }
+
+                    }
+                }
+            }
+
+        }
+
+        private void WarmUpLog()
+        {
+            try
+            {
+                using (var log = new ConnectionLogDBContext())
+                {
+                    log.MachineConnectionLog.ToList();
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.ToString());
+            }
+
+
+        }
+
+        private void WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false)
+        {
+            try
+            {
+
+                if (clientData == null || string.IsNullOrEmpty(data)) return;
+
+                if (clientData.ChargeBoxId == null)
+                {
+                    logger.Fatal(clientData.Path + "]********************session ChargeBoxId null sessionId=" + clientData.SessionID);
+                }
+                using (var db = new ConnectionLogDBContext())
+                {
+                    string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
+                          "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session";
+                    var dd = DateTime.UtcNow;
+                    SqlParameter[] parameter =
+                    {
+                      new SqlParameter("CreatedOn",dd),
+                      new SqlParameter("ChargeBoxId",clientData.ChargeBoxId==null?"unknown":clientData.ChargeBoxId.Replace("'","''")),
+                      new SqlParameter("MessageType",messageType.Replace("'","''")),
+                      new SqlParameter("Data",data.Replace("'","''")),
+                      new SqlParameter("Msg",errorMsg.Replace("'","''")),
+                      new  SqlParameter("IsSent",isSent),
+                      new  SqlParameter("EVSEEndPoint",clientData.RemoteEndPoint==null?"123":clientData.RemoteEndPoint.ToString()),
+                      new  SqlParameter("Session",clientData.SessionID==null?"123":clientData.SessionID)
+               };
+
+                    db.Database.ExecuteSqlCommand(sp, parameter);
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.ToString());
+            }
+
+
+        }
+    }
+}

+ 36 - 0
EVCB_OCPP.WSServer.backup/Service/BusinessServiceFactory.cs

@@ -0,0 +1,36 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Packet.Messages.SubTypes;
+using EVCB_OCPP.WSServer.Dto;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Service
+{
+
+    public interface IBusinessService
+    {
+        Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag);
+
+        Task NotifyFaultStatus(ErrorDetails details);
+
+        Task NotifyConnectorUnplugged(string chargeBoxId,string data);
+
+    }
+
+    static public class BusinessServiceFactory
+    {
+
+        static public IBusinessService CreateBusinessService(string customerId)
+        {
+            bool isCallOut = false;
+            using (var db = new MainDBContext())
+            {
+                isCallOut = db.Customer.Where(x => x.Id == new Guid(customerId)).Select(x => x.CallPartnerApiOnSchedule).SingleOrDefault();
+            }
+
+            return isCallOut ? new OuterBusinessService(customerId) : (IBusinessService)new LocalBusinessService(customerId);
+        }
+
+    }
+}

+ 365 - 0
EVCB_OCPP.WSServer.backup/Service/HttpClientService.cs

@@ -0,0 +1,365 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Service
+{
+    public class HttpClientService
+    {
+        /// <summary>
+        /// 要求逾時前等候的時間長度
+        /// #網域名稱系統(DNS)查詢最多可能需要15秒的時間才會傳回或超時
+        /// 預設60秒
+        /// </summary>
+        public int Timeout { get => _timeout; set => _timeout = value; }
+
+        /// <summary>
+        /// 取得或設定使用 HttpClient 物件提出要求時,所允許的同時連線 數目上限 (每個伺服器端點)。
+        /// 請注意,此限制是按照每個伺服器端點計算,例如值 256 允許 http://www.adatum.com/ 使用 256 個同時連線,
+        /// 而 http://www.adventure-works.com/ 另有 256 個同時連線。
+        /// 預設100個
+        /// </summary>
+        public int MaxConnectionsPerServer { get => _maxConnectionsPerServer; set => _maxConnectionsPerServer = value; }
+
+
+        /// <summary>
+        /// 設定HttpMessageHandler的生命週期,如果其存留期間尚未過期,HttpMessageHandler 執行個體可從集區重複使用(建立新的 HttpClient 執行個體時)
+        /// 因為處理常式通常會管理自己專屬的底層 HTTP 連線。 建立比所需數目更多的處理常式,可能會導致連線延遲。 有些處理常式也會保持連線無限期地開啟,這可能導致處理常式無法回應 DNS (網域名稱系統)變更。
+        /// 預設處理常式存留時間為120秒。
+        /// </summary>
+        public int HandlerLifetime { get => _handlerLifetime; set => _handlerLifetime = value; }
+
+
+        private IHttpClientFactory _clientFactory = null;
+        private IServiceCollection _services = new ServiceCollection();
+        private int _handlerLifetime = 2;
+        private int _maxConnectionsPerServer = 300;
+        private int _timeout = 60;
+
+
+        public HttpClientService(string baseAddress = "")
+        {
+
+            _services.AddHttpClient("Default", c =>
+            {
+                if (!string.IsNullOrEmpty(baseAddress))
+                {
+                    c.BaseAddress = new Uri(baseAddress);
+                }
+                c.Timeout = TimeSpan.FromSeconds(_timeout);
+                c.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
+            })
+          .AddTypedClient<HttpClient>().SetHandlerLifetime(TimeSpan.FromMinutes(_handlerLifetime)).ConfigurePrimaryHttpMessageHandler((h =>
+          {
+              return new HttpClientHandler
+              {
+
+                  MaxConnectionsPerServer = _maxConnectionsPerServer
+
+              };
+          }));
+
+            Init();
+        }
+
+
+        private void Init()
+        {
+            _clientFactory = _services.BuildServiceProvider()
+                     .GetRequiredService<IHttpClientFactory>();
+
+
+        }
+
+
+        public virtual async Task<HttpResponse> PostJsonAsync(string Url, string bodyData, Dictionary<string, string> headers, string clientName = "Default", bool bearerToken = false, string authorizationToken = null)
+        {
+            HttpResponse result = new HttpResponse() { IsError = false };
+
+            try
+            {
+                var client = _clientFactory.CreateClient(clientName);
+
+                if (!string.IsNullOrEmpty(authorizationToken))
+                {
+                    client.DefaultRequestHeaders.Authorization = bearerToken ? new AuthenticationHeaderValue("Bearer", authorizationToken) : new AuthenticationHeaderValue(authorizationToken);
+                }
+                if (headers != null)
+                {
+                    for (int idx = 0; idx < headers.Count; idx++)
+                    {
+                        client.DefaultRequestHeaders.Add(headers.ElementAt(idx).Key, headers.ElementAt(idx).Value);
+                    }
+                }
+
+                HttpContent content = new StringContent(bodyData);
+                content.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
+                content.Headers.ContentType.CharSet = "UTF-8";
+
+                var response = await client.PostAsync(Url, content).ConfigureAwait(false);
+
+                result.IsSuccessStatusCode = response.IsSuccessStatusCode;
+                result.Headers = response.Headers;
+                result.RequestMessage = response.RequestMessage;
+                result.StatusCode = response.StatusCode;
+                result.Response = await response.Content.ReadAsStringAsync();
+
+
+
+            }
+            catch (Exception ex)
+            {
+                result.IsError = true;
+                result.Exception = ex;
+
+            }
+
+
+            return result;
+        }
+
+        public virtual async Task<HttpResponse> GetJsonAsync(string Url, Dictionary<string, string> headers, string clientName = "Default", bool bearerToken = false, string authorizationToken = null)
+        {
+            HttpResponse result = new HttpResponse() { IsError = false };
+
+            try
+            {
+                var client = _clientFactory.CreateClient(clientName);
+
+                if (!string.IsNullOrEmpty(authorizationToken))
+                {
+                    client.DefaultRequestHeaders.Authorization = bearerToken ? new AuthenticationHeaderValue("Bearer", authorizationToken) : new AuthenticationHeaderValue(authorizationToken);
+                }
+
+                if (headers != null)
+                {
+                    for (int idx = 0; idx < headers.Count; idx++)
+                    {
+                        client.DefaultRequestHeaders.Add(headers.ElementAt(idx).Key, headers.ElementAt(idx).Value);
+                    }
+                }
+
+                // client.DefaultRequestHeaders.Add("Content-Type", "application/json");
+
+
+                var response = await client.GetAsync(Url).ConfigureAwait(false);
+
+                result.IsSuccessStatusCode = response.IsSuccessStatusCode;
+                result.Headers = response.Headers;
+                result.RequestMessage = response.RequestMessage;
+                result.StatusCode = response.StatusCode;
+                result.Response = await response.Content.ReadAsStringAsync();
+
+
+
+            }
+            catch (Exception ex)
+            {
+                result.IsError = true;
+                result.Exception = ex;
+
+            }
+
+
+            return result;
+        }
+
+        public virtual async Task<HttpResponse> PutJsonAsync(string Url, string bodyData, Dictionary<string, string> headers, string clientName = "Default", bool bearerToken = false, string authorizationToken = null)
+        {
+            HttpResponse result = new HttpResponse() { IsError = false };
+
+            try
+            {
+                var client = _clientFactory.CreateClient(clientName);
+
+                if (!string.IsNullOrEmpty(authorizationToken))
+                {
+                    client.DefaultRequestHeaders.Authorization = bearerToken ? new AuthenticationHeaderValue("Bearer", authorizationToken) : new AuthenticationHeaderValue(authorizationToken);
+                }
+                if (headers != null)
+                {
+                    for (int idx = 0; idx < headers.Count; idx++)
+                    {
+                        client.DefaultRequestHeaders.Add(headers.ElementAt(idx).Key, headers.ElementAt(idx).Value);
+                    }
+                }
+
+                HttpContent content = new StringContent(bodyData);
+                content.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
+                content.Headers.ContentType.CharSet = "UTF-8";
+
+                var response = await client.PutAsync(Url, content).ConfigureAwait(false);
+
+                result.IsSuccessStatusCode = response.IsSuccessStatusCode;
+                result.Headers = response.Headers;
+                result.RequestMessage = response.RequestMessage;
+                result.StatusCode = response.StatusCode;
+                result.Response = await response.Content.ReadAsStringAsync();
+
+
+
+            }
+            catch (Exception ex)
+            {
+                result.IsError = true;
+                result.Exception = ex;
+
+            }
+
+
+            return result;
+        }
+
+        public virtual async Task<HttpResponse> DeleteJsonAsync(string Url, Dictionary<string, string> headers, string clientName = "Default", bool bearerToken = false, string authorizationToken = null)
+        {
+            HttpResponse result = new HttpResponse() { IsError = false };
+
+            try
+            {
+                var client = _clientFactory.CreateClient(clientName);
+
+                if (!string.IsNullOrEmpty(authorizationToken))
+                {
+                    client.DefaultRequestHeaders.Authorization = bearerToken ? new AuthenticationHeaderValue("Bearer", authorizationToken) : new AuthenticationHeaderValue(authorizationToken);
+                }
+
+                if (headers != null)
+                {
+                    for (int idx = 0; idx < headers.Count; idx++)
+                    {
+                        client.DefaultRequestHeaders.Add(headers.ElementAt(idx).Key, headers.ElementAt(idx).Value);
+                    }
+                }
+
+                //   client.DefaultRequestHeaders.Add("Content-Type", "application/json");
+
+
+                var response = await client.DeleteAsync(Url).ConfigureAwait(false);
+
+                result.IsSuccessStatusCode = response.IsSuccessStatusCode;
+                result.Headers = response.Headers;
+                result.RequestMessage = response.RequestMessage;
+                result.StatusCode = response.StatusCode;
+                result.Response = await response.Content.ReadAsStringAsync();
+
+
+
+            }
+            catch (Exception ex)
+            {
+                result.IsError = true;
+                result.Exception = ex;
+
+            }
+
+
+            return result;
+        }
+
+        public virtual async Task<HttpResponse> PostFormDataAsync(string Url, Dictionary<string, string> bodyData, Dictionary<string, string> headers, string clientName = "Default", bool bearerToken = false, string authorizationToken = null)
+        {
+            HttpResponse result = new HttpResponse() { IsError = false };
+
+            try
+            {
+                var client = _clientFactory.CreateClient(clientName);
+
+                ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
+
+                if (!string.IsNullOrEmpty(authorizationToken))
+                {
+                    client.DefaultRequestHeaders.Authorization = bearerToken ? new AuthenticationHeaderValue("Bearer", authorizationToken) : new AuthenticationHeaderValue(authorizationToken);
+                }
+                if (headers != null)
+                {
+                    for (int idx = 0; idx < headers.Count; idx++)
+                    {
+                        client.DefaultRequestHeaders.Add(headers.ElementAt(idx).Key, headers.ElementAt(idx).Value);
+                    }
+                }
+
+                var content = new MultipartFormDataContent();
+
+                foreach (var keyValuePair in bodyData)
+                {
+                    content.Add(new StringContent(keyValuePair.Value), "\"" + keyValuePair.Key + "\"");
+                }
+
+                var response = await client.PostAsync(Url, content).ConfigureAwait(false);
+
+
+
+                result.IsSuccessStatusCode = response.IsSuccessStatusCode;
+                result.Headers = response.Headers;
+                result.RequestMessage = response.RequestMessage;
+                result.StatusCode = response.StatusCode;
+                result.Response = await response.Content.ReadAsStringAsync();
+
+
+
+            }
+            catch (Exception ex)
+            {
+                result.IsError = true;
+                result.Exception = ex;
+
+            }
+
+
+            return result;
+        }
+
+
+
+    }
+
+
+    public class HttpResponse
+    {
+        public bool IsError { internal set; get; }
+
+        public Exception Exception { internal set; get; }
+
+        public string Response { internal set; get; }
+
+        /// <summary>
+        /// 摘要:
+        ///     取得或設定 HTTP 回應的狀態碼。
+        /// 傳回:
+        ///    HTTP 回應的狀態碼。
+        /// </summary>
+        public HttpStatusCode StatusCode { get; internal set; }
+
+
+        /// <summary>
+        /// 摘要:
+        ///      取得 HTTP 回應標頭的集合。
+        /// 傳回:
+        ///     HTTP 回應標頭的集合。
+        /// </summary>
+        public HttpResponseHeaders Headers { get; internal set; }
+
+
+        /// <summary>
+        /// 摘要:
+        ///     取得或設定導致此回應訊息的要求訊息。
+        /// 傳回:
+        ///       導致此回應訊息的要求訊息。
+        /// </summary>
+        public HttpRequestMessage RequestMessage { get; internal set; }
+
+        /// <summary>
+        /// 摘要:
+        ///   取得指示 HTTP 回應是否成功的值。
+        /// 傳回:
+        ///       指示 HTTP 回應是否成功的值。 如果 System.Net.Http.HttpResponseMessage.StatusCode 在 200-299
+        ///     的範圍內,則為 true;否則為 false。
+        /// </summary>
+        public bool IsSuccessStatusCode { get; internal set; }
+    }
+}

+ 393 - 0
EVCB_OCPP.WSServer.backup/Service/LoadingBalanceService.cs

@@ -0,0 +1,393 @@
+using Dapper;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.SqlClient;
+using System.Linq;
+
+namespace EVCB_OCPP.WSServer.Service
+{
+    public class LoadBalanceSetting
+    {
+        public int StationId { set; get; }
+
+        public int LBMode { set; get; }
+
+        public int LBCurrent { set; get; }
+
+    }
+
+    public class LoadingBalanceService
+    {
+        string mainConnectionString = ConfigurationManager.ConnectionStrings["MainDBContext"].ConnectionString;
+        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+
+        ConcurrentDictionary<int, object> _lockDic = new ConcurrentDictionary<int, object>();
+
+
+        public LoadingBalanceService()
+        {
+
+        }
+
+        public int GetStationIdByMachineId(string machineId)
+        {
+            int stationId = 0;
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                string strSql = "Select StationId from [dbo].[StationMachine] where MachineId=@MachineId ; ";
+                stationId = conn.ExecuteScalar<Int32>(strSql, parameters);
+            }
+            return stationId;
+        }
+
+
+        public bool IsNeedtoCancelSetting(int stationId, string machineId, string chargeBoxId)
+        {
+            var setting = GetLoadBalance(stationId);
+            if (setting == null) return false;
+
+            lock (GetLock(stationId))
+            {
+                if (setting.LBMode > 0 && setting.LBMode < 3 && !IsStillInTransactions(chargeBoxId))
+                {
+                    // renew table
+                    UpdateLoadbalanceRecord(stationId, machineId, 0, DateTime.UtcNow);
+                    return true;
+
+                }
+
+                if (setting.LBMode >= 3 || setting.LBMode < 1)
+                {
+                    CloseLoadbalanceRecord(stationId);
+
+                }
+            }
+
+            return false;
+
+        }
+
+        private object GetLock(int stationId)
+        {
+
+            if (!_lockDic.ContainsKey(stationId))
+            {
+                _lockDic.TryAdd(stationId, new object());
+            }
+
+            return _lockDic[stationId];
+
+        }
+        private void CloseLoadbalanceRecord(int stationId)
+        {
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                parameters.Add("@FinishedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
+                string strSql = "Update  [dbo].[LoadingBalance]  SET FinishedOn=@FinishedOn where StationId=@StationId and FinishedOn='1991/01/01'; ";
+                conn.Execute(strSql, parameters);
+
+            }
+        }
+
+
+        private void UpdateLoadbalanceRecord(int stationId, string machineId, decimal power, DateTime? finishedOn, bool keepgoing = false)
+        {
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                if (finishedOn.HasValue)
+                {
+                    var parameters = new DynamicParameters();
+                    parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                    parameters.Add("@FinishedOn", finishedOn.Value, DbType.DateTime, ParameterDirection.Input);
+                    string strSql = "Update  [dbo].[LoadingBalance]  SET FinishedOn=@FinishedOn where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
+                    conn.Execute(strSql, parameters);
+                }
+                else
+                {
+                    if (keepgoing)
+                    {
+                        var parameters = new DynamicParameters();
+                        parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                        parameters.Add("@Power", power, DbType.Decimal, ParameterDirection.Input);
+                        string strSql = "Update  [dbo].[LoadingBalance]  SET Power=@Power where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
+                        conn.Execute(strSql, parameters);
+                    }
+                    else
+                    {
+                        var parameters = new DynamicParameters();
+                        parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                        parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                        parameters.Add("@Power", power, DbType.Decimal, ParameterDirection.Input);
+                        parameters.Add("@CreatedOn", DateTime.UtcNow, DbType.DateTime, ParameterDirection.Input);
+                        parameters.Add("@FinishedOn", new DateTime(1991, 1, 1, 0, 0, 0, DateTimeKind.Utc), DbType.DateTime, ParameterDirection.Input);
+
+                        string strSql = "INSERT INTO [dbo].[LoadingBalance] " +
+                         "([StationId],[MachineId],[Power],[CreatedOn],[FinishedOn]) " +
+                         "VALUES(@StationId,@MachineId,@Power,@CreatedOn,@FinishedOn);";
+
+                        conn.Execute(strSql, parameters);
+                    }
+
+                }
+
+            }
+        }
+
+
+        private bool IsStillInTransactions(string chargeBoxId)
+        {
+            bool result = false;
+
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@ChargeBoxId", chargeBoxId, DbType.String, ParameterDirection.Input);
+                string strSql = "Select count(*) from [dbo].[TransactionRecord] where ChargeBoxId=@ChargeBoxId and StopTime='1991/01/01'; ";
+                result = conn.ExecuteScalar<bool>(strSql, parameters);
+            }
+
+            return result;
+        }
+
+        private decimal? GetCurrentSetting(string machineId)
+        {
+            decimal? result = (decimal?)null;
+
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@MachineId", machineId, DbType.String, ParameterDirection.Input);
+                string strSql = "Select Power from [dbo].[LoadingBalance] where MachineId=@MachineId and FinishedOn='1991/01/01'; ";
+                result = conn.ExecuteScalar<decimal>(strSql, parameters);
+            }
+
+            return result;
+        }
+
+
+
+        public Dictionary<string, decimal?> GetRerangeSettingPower(int stationId)
+        {
+            Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
+            var setting = GetLoadBalance(stationId);
+            if (setting == null) return null;
+
+            lock (GetLock(stationId))
+            {
+                if (setting != null && setting.LBMode == 2)
+                {
+                    string machineId = string.Empty;
+                    decimal ratedPower = GetRatedPower(machineId);
+                    //找站內最早要充電的交易 下發充電Power & 填寫新給的Power
+                    using (SqlConnection conn = new SqlConnection(mainConnectionString))
+                    {
+                        var parameters = new DynamicParameters();
+                        parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                        string strSql = "Select M.Id from [dbo].[LoadingBalance] LB,  [dbo].[Machine] M  where LB.StationId=@StationId and  LB.MachineId=M.Id and LB.Power < M.RatedPower and LB.FinishedOn='1991/01/01' order by LB.Id asc; ";
+                        machineId = conn.ExecuteScalar<string>(strSql, parameters);
+                    }
+
+                    if (!string.IsNullOrEmpty(machineId))
+                    {
+                        decimal estimatedPwerValue = GetFCFSPower(stationId, machineId, setting.LBCurrent);
+
+                        // renew table
+                        UpdateLoadbalanceRecord(stationId, machineId, estimatedPwerValue, null, true);
+                        // UpdateLoadbalanceRecord(stationId, machineId, estimatedPwerValue, null);
+
+                        dic.Add(machineId, estimatedPwerValue);
+                    }
+
+
+                }
+
+                if (setting != null && setting.LBMode == 1)
+                {
+                    dic = GetAveragePower(stationId, setting.LBCurrent);
+                    foreach (var kv in dic)
+                    {
+                        if (kv.Value.HasValue)
+                        {
+                            UpdateLoadbalanceRecord(stationId, kv.Key, 0, DateTime.UtcNow);
+                            UpdateLoadbalanceRecord(stationId, kv.Key, kv.Value.Value, null);
+                        }
+
+                    }
+                }
+            }
+
+
+            return dic;
+
+        }
+
+        public Dictionary<string, decimal?> GetSettingPower(int stationId, string machineId)
+        {
+            Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
+            var setting = GetLoadBalance(stationId);
+            if (setting == null) return null;
+
+            lock (GetLock(stationId))
+            {
+
+                if (setting != null)
+                {
+                    if (setting.LBMode == 1)
+                    {
+                        dic = GetAveragePower(stationId, setting.LBCurrent, machineId);
+                        foreach (var kv in dic)
+                        {
+                            if (kv.Value.HasValue)
+                            {
+                                UpdateLoadbalanceRecord(stationId, kv.Key, 0, DateTime.UtcNow);
+                                UpdateLoadbalanceRecord(stationId, kv.Key, kv.Value.Value, null);
+                            }
+
+                        }
+                    }
+                    else if (setting.LBMode == 2)
+                    {
+                        dic.Add(machineId, GetFCFSPower(stationId, machineId, setting.LBCurrent));
+
+                        UpdateLoadbalanceRecord(stationId, machineId, 0, DateTime.UtcNow);
+                        UpdateLoadbalanceRecord(stationId, machineId, dic[machineId].Value, null);
+
+                    }
+                    else
+                    {
+                        // 把LB TABLE 關閉
+                        CloseLoadbalanceRecord(stationId);
+
+                    }
+                }
+
+            }
+
+            return dic;
+        }
+
+
+        public LoadBalanceSetting GetLoadBalance(int stationId)
+        {
+            LoadBalanceSetting setting = null;
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+
+                string strSql = "Select LBMode,LBCurrent from [dbo].[Station] where Id=@StationId ; ";
+                setting = conn.Query<LoadBalanceSetting>(strSql, parameters).FirstOrDefault();
+            }
+            return setting;
+        }
+
+        private List<string> GetIdsbyStationId(int stationId)
+        {
+            List<string> machineIds = new List<string>();
+            using (SqlConnection conn = new SqlConnection(webConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int16, ParameterDirection.Input);
+                string strSql = "Select MachineId from [dbo].[StationMachine] where StationId=@StationId; ";
+                machineIds = conn.Query<String>(strSql, parameters).ToList();
+            }
+            return machineIds;
+        }
+
+
+
+        private Dictionary<string, decimal?> GetAveragePower(int stationId, int availableCapacity, string machineId = "")
+        {
+            Dictionary<string, decimal?> dic = new Dictionary<string, decimal?>();
+            //總量 * 該樁的額定功率/該站充電中樁的總額定功率
+            List<string> _MachineIds = new List<string>();
+            int skipCount = 0;
+            int size = 200;
+            int takeCount = 0;
+            int totalRatePower = 0;
+
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                string strSql = "Select MachineId from [dbo].[LoadingBalance] where StationId=@StationId and FinishedOn='1991/01/01'; ";
+                _MachineIds = conn.Query<string>(strSql, parameters).ToList();
+            }
+
+            if (!string.IsNullOrEmpty(machineId) && !_MachineIds.Contains(machineId))
+            {
+                _MachineIds.Add(machineId);
+            }
+
+            while (skipCount < _MachineIds.Count())
+            {
+                takeCount = _MachineIds.Count() - skipCount > size ? size : _MachineIds.Count() - skipCount;
+
+                using (SqlConnection conn = new SqlConnection(mainConnectionString))
+                {
+                    string strSql = "Select Sum(RatedPower) from [dbo].[Machine] where Id in @machineIds and [Online]=1; ";
+                    totalRatePower += conn.ExecuteScalar<Int32>(strSql, new { machineIds = _MachineIds.ToArray() });
+                    skipCount += takeCount;
+                }
+            }
+
+            foreach (var id in _MachineIds)
+            {
+                int singleRatePower = (int)GetRatedPower(id);
+                var value = totalRatePower == 0 ? 0 : availableCapacity * singleRatePower / totalRatePower;
+                dic.Add(id, value);
+            }
+
+            return dic;
+
+        }
+
+        private decimal GetRatedPower(string machineId)
+        {
+            decimal ratedPower = 0;
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@machineId", machineId, DbType.String, ParameterDirection.Input);
+                string strSql = "Select RatedPower from [dbo].[Machine] where Id=@machineId; ";
+                ratedPower = conn.ExecuteScalar<Int32>(strSql, parameters);
+            }
+            return ratedPower;
+        }
+
+        private decimal GetFCFSPower(int stationId, string machineId, int availableCapacity)
+        {
+
+            decimal ongoingPower = 0;
+            decimal singleRatePower = GetRatedPower(machineId);
+
+            //先找LB 裡面目前下發的Power
+            decimal? currentPower = GetCurrentSetting(machineId);
+
+            if (!currentPower.HasValue) currentPower = 0;
+
+            //總量 - 所有正在進行的Power
+            using (SqlConnection conn = new SqlConnection(mainConnectionString))
+            {
+                var parameters = new DynamicParameters();
+                parameters.Add("@StationId", stationId, DbType.Int32, ParameterDirection.Input);
+                string strSql = "Select Sum(Power) from [dbo].[LoadingBalance] where StationId=@StationId and FinishedOn='1991/01/01'; ";
+                ongoingPower = conn.ExecuteScalar<Int32>(strSql, parameters);
+            }
+
+            return availableCapacity - (ongoingPower - currentPower.Value) > singleRatePower ? singleRatePower :
+                (availableCapacity - (ongoingPower - currentPower.Value) > 0 ? availableCapacity - (ongoingPower - currentPower.Value) : 0);
+        }
+
+
+    }
+}
+

+ 92 - 0
EVCB_OCPP.WSServer.backup/Service/LocalBusinessService.cs

@@ -0,0 +1,92 @@
+using EVCB_OCPP.Packet.Messages.SubTypes;
+using EVCB_OCPP.WSServer.Dto;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Net;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Service
+{
+    public class LocalBusinessService : IBusinessService
+    {
+
+        string customerId = string.Empty;
+
+        public LocalBusinessService(string customerId)
+        {
+            this.customerId = customerId;
+        }
+
+        async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag)
+        {
+            await Task.Delay(10);
+            IdTokenInfo info = new IdTokenInfo() { IdTagInfo = new IdTagInfo() { status = AuthorizationStatus.Invalid } };
+
+            try
+            {
+                if (customerId.ToUpper() == "009E603C-79CD-4620-A2B8-D9349C0E8AD8")
+                {
+                    info.IdTagInfo = new IdTagInfo() { status = AuthorizationStatus.Accepted };
+                    return info;
+                }
+
+
+                OuterHttpClient _client = new OuterHttpClient();
+
+
+                string url = ConfigurationManager.AppSettings["LocalAuthAPI"];
+
+
+                HttpClientService service = new HttpClientService();
+
+                Dictionary<string, string> postData = new Dictionary<string, string>()
+                {
+                  { "ChargeBoxId", chargeBoxId },
+                  { "IdTag", idTag },
+
+
+                };
+                var _innerresult = await service.PostFormDataAsync(url, postData, null);
+
+
+                if (_innerresult.StatusCode == HttpStatusCode.OK)
+                {
+                    JObject jo = JObject.Parse(_innerresult.Response);
+                    if (jo["code"].ToString() == "1")
+                    {
+                        try
+                        {
+                            info.IdTagInfo.status = (AuthorizationStatus)Enum.Parse(typeof(AuthorizationStatus), jo["message"].ToString());
+                        }
+                        catch (Exception)
+                        {
+                            ;
+                        }
+
+
+                    }
+
+                }
+
+            }
+            catch (Exception ex)
+            {
+                ;
+            }
+            return info;
+
+        }
+
+        async public Task NotifyConnectorUnplugged(string chargeBoxId, string data)
+        {
+            await Task.Delay(10);
+        }
+
+        async public Task NotifyFaultStatus(ErrorDetails details)
+        {
+            await Task.Delay(10);
+        }
+    }
+}

+ 240 - 0
EVCB_OCPP.WSServer.backup/Service/OuterBusinessService.cs

@@ -0,0 +1,240 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.Packet.Messages.SubTypes;
+using EVCB_OCPP.WSServer.Dto;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using NLog;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Service
+{
+    internal class CPOOuterResponse
+    {
+        public CPOOuterResponse()
+        {
+            StatusCode = 0;
+
+        }
+
+        public int StatusCode { set; get; }
+
+        public string StatusMessage { set; get; }
+
+        public string Data { set; get; }
+
+        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+        public string SerialNo { set; get; }
+
+
+        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+        public string ErrorDetail { set; get; }
+
+
+    }
+    internal class CustomerSignMaterial
+    {
+        internal bool CallsThirdParty { set; get; }
+
+        internal string Id { set; get; }
+
+        internal string APIUrl { set; get; }
+
+        internal string SaltKey { set; get; }
+    }
+    public class OuterBusinessService : IBusinessService
+    {
+        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        private OuterHttpClient httpClient = new OuterHttpClient();
+        private CustomerSignMaterial signMaterial = null;
+        private string CustomerId = string.Empty;
+        public OuterBusinessService(string customerId)
+        {
+            CustomerId = customerId;
+            signMaterial = GetSign(customerId);
+        }
+
+
+        async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag)
+        {
+            await Task.Delay(10);
+            IdTokenInfo result = new IdTokenInfo() { IdTagInfo = new IdTagInfo() { status = AuthorizationStatus.Invalid } };
+
+            try
+            {
+                string requestParams = string.Format("charging_auth?ChargeBoxId={0}&IdTag={1}", chargeBoxId, idTag);
+
+               // if (CustomerId.ToLower() == "9e6bfdcc-09fb-4dab-a428-43fe507600a3")
+                {
+                    logger.Info(chargeBoxId + " Charging Monitor======================================>");
+                    logger.Info(signMaterial.APIUrl + requestParams);
+                }
+                var response = await httpClient.Post(signMaterial.APIUrl + requestParams, new Dictionary<string, string>()
+                            {
+                                { "PartnerId",signMaterial.Id}
+
+                            }, null, signMaterial.SaltKey).ConfigureAwait(false);
+               // if (CustomerId.ToLower() == "9e6bfdcc-09fb-4dab-a428-43fe507600a3")
+                {
+                    logger.Info(JsonConvert.SerializeObject(response));
+                }
+                if (response.Success)
+                {
+                    Console.WriteLine(response.Response);
+                    var _httpResult = JsonConvert.DeserializeObject<CPOOuterResponse>(response.Response);
+                    JObject jo = JObject.Parse(_httpResult.Data);
+
+                    if (jo.ContainsKey("ExpiryDate"))
+                    {
+                        DateTime dt = jo["ExpiryDate"].Value<DateTime>();
+                        result.IdTagInfo.expiryDate = dt;
+                    }
+
+                    if (jo.ContainsKey("ParentIdTag"))
+                    {
+                        string _Message = jo["ParentIdTag"].Value<string>();
+                        result.IdTagInfo.parentIdTag = _Message;
+
+                    }
+
+                    if (jo.ContainsKey("ChargePointFee"))
+                    {
+                       
+
+                        for(int i=0;i< jo["ChargePointFee"].Count();i++)
+                        {
+                            if(i==0)
+                            {
+                                result.ChargePointFee = new List<ChargePointFee>();
+                            }
+                            result.ChargePointFee.Add(jo["ChargePointFee"][i].ToObject<ChargePointFee>());
+                        }
+                     
+                    }
+
+                    if (jo.ContainsKey("ChargepointFee"))
+                    {                       
+
+                        for (int i = 0; i < jo["ChargepointFee"].Count(); i++)
+                        {
+                            if (i == 0)
+                            {
+                                result.ChargePointFee = new List<ChargePointFee>();
+                            }
+
+                            result.ChargePointFee.Add(jo["ChargepointFee"][i].ToObject<ChargePointFee>());
+                        }
+
+                    }
+
+                    if (jo.ContainsKey("AccountBalance"))
+                    {
+                        decimal accountBalance = jo["AccountBalance"].Value<decimal>();
+                        result.AccountBalance = accountBalance;
+                    }
+
+
+                    if (jo.ContainsKey("Status"))
+                    {
+                        string _Message = jo["Status"].Value<string>();
+                        result.IdTagInfo.status = (AuthorizationStatus)Enum.Parse(typeof(AuthorizationStatus), _Message);
+                    }
+                }
+                else
+                {
+                    logger.Error(chargeBoxId + " OuterBusinessService.Authorize Fail: " + response.Response);
+                }
+
+            }
+            catch (Exception ex)
+            {
+                result.IdTagInfo.status = AuthorizationStatus.Invalid;
+
+                logger.Error(chargeBoxId + " OuterBusinessService.Authorize Ex: " + ex.ToString());
+            }
+
+            return result;
+
+        }
+
+        async public Task NotifyFaultStatus(ErrorDetails details)
+        {
+
+            try
+            {
+                if (signMaterial.CallsThirdParty)
+                {
+
+              
+
+
+                    var response = await httpClient.Post(signMaterial.APIUrl + "connectorfault", new Dictionary<string, string>()
+                            {
+                                { "PartnerId",signMaterial.Id}
+
+                            }, details, signMaterial.SaltKey).ConfigureAwait(false);
+
+                  
+                   
+                }
+
+
+            }
+            catch (Exception ex)
+            {
+
+                logger.Error(details.ChargeBoxId + " OuterBusinessService.NotifyFaultStatus Ex: " + ex.ToString());
+            }
+
+
+        }
+
+        async public Task NotifyConnectorUnplugged(string chargeBoxId, string data)
+        {
+            try
+            {
+                JObject jo = JObject.Parse(data);
+
+                var details = new { ChargeBoxId = chargeBoxId, SessionId = jo["idTx"].Value<Int32>(), Timestamp = jo["timestamp"].Value<DateTime>() };
+                if (signMaterial.CallsThirdParty)
+                {
+                    var response = await httpClient.Post(signMaterial.APIUrl + "connectorunplugged", new Dictionary<string, string>()
+                            {
+                                { "PartnerId",signMaterial.Id}
+
+                            }, details, signMaterial.SaltKey).ConfigureAwait(false);
+
+
+                }
+
+
+            }
+            catch (Exception ex)
+            {
+
+                logger.Error(chargeBoxId + " OuterBusinessService.NotifyConnectorUnplugged Ex: " + ex.ToString());
+            }
+
+        }
+
+        private CustomerSignMaterial GetSign(string customerId)
+        {
+            Guid Id = new Guid(customerId);
+            CustomerSignMaterial _customer = new CustomerSignMaterial();
+
+
+            using (var db = new MainDBContext())
+            {
+                _customer = db.Customer.Where(x => x.Id == Id).Select(x => new CustomerSignMaterial() { Id = x.Id.ToString(), APIUrl = x.ApiUrl, SaltKey = x.ApiKey, CallsThirdParty = x.CallPartnerApiOnSchedule }).FirstOrDefault();
+            }
+            return _customer;
+        }
+
+        public Task NotifyConnectorUnplugged(string data)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

+ 214 - 0
EVCB_OCPP.WSServer.backup/Service/OuterHttpClient.cs

@@ -0,0 +1,214 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Service
+{
+    public class OuterHttpClient
+    {
+        private HttpClientService httpClient = new HttpClientService();
+
+        async public Task<HttpResult> Post(string url, Dictionary<string, string> headers, object requestBody, string saltkey)
+        {
+            HttpResult result = new HttpResult() { Success = false };
+
+            try
+            {
+                string body = PreAction(url, ref headers, requestBody, saltkey);
+                var _response = await httpClient.PostJsonAsync(url, body, headers);
+
+                result.Response = _response.Response;
+                result.Status = _response.StatusCode;
+                result.Success = _response.IsSuccessStatusCode;
+                result.Exception = _response.Exception;
+
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+            }
+
+            return result;
+        }
+
+
+        async public Task<HttpResult> PostFormDataAsync(string url, Dictionary<string, string> bodyData, Dictionary<string, string> headers, string clientName = "Default", bool bearerToken = false, string authorizationToken = null)
+        {
+            HttpResult result = new HttpResult() { Success = false };
+
+            try
+            {
+
+                var _response = await httpClient.PostFormDataAsync(url, bodyData, null);
+
+                result.Response = _response.Response;
+                result.Status = _response.StatusCode;
+                result.Success = _response.IsSuccessStatusCode;
+                result.Exception = _response.Exception;
+
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+            }
+
+            return result;
+        }
+
+        async public Task<HttpResult> GetWeather(string url, Dictionary<string, string> headers, string saltkey)
+        {
+
+            HttpResult result = new HttpResult() { Success = false };
+
+            try
+            {
+               // string body = PreAction(url, ref headers, null, saltkey);
+                var _response = await httpClient.GetJsonAsync(url, headers);
+                result.Response = _response.Response;
+                result.Status = _response.StatusCode;
+                result.Success = _response.IsSuccessStatusCode;
+                result.Exception = _response.Exception;
+
+
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+            }
+
+            return result;
+        }
+
+
+
+        async public Task<HttpResult> Get(string url, Dictionary<string, string> headers, string saltkey)
+        {
+
+            HttpResult result = new HttpResult() { Success = false };
+
+            try
+            {
+                string body = PreAction(url, ref headers, null, saltkey);
+                var _response = await httpClient.GetJsonAsync(url, headers);
+                result.Response = _response.Response;
+                result.Status = _response.StatusCode;
+                result.Success = _response.IsSuccessStatusCode;
+                result.Exception = _response.Exception;
+
+
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+            }
+
+            return result;
+        }
+
+        async public Task<HttpResult> Delete(string url, Dictionary<string, string> headers, string saltkey)
+        {
+            HttpResult result = new HttpResult() { Success = false };
+
+            try
+            {
+                string body = PreAction(url, ref headers, null, saltkey);
+                var _response = await httpClient.DeleteJsonAsync(url, headers);
+                result.Response = _response.Response;
+                result.Status = _response.StatusCode;
+                result.Success = _response.IsSuccessStatusCode;
+                result.Exception = _response.Exception;
+
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+            }
+
+            return result;
+        }
+
+        async public Task<HttpResult> Put(string url, Dictionary<string, string> headers, object requestBody, string saltkey)
+        {
+            HttpResult result = new HttpResult() { Success = false };
+
+            try
+            {
+                string body = PreAction(url, ref headers, requestBody, saltkey);
+                var _response = await httpClient.PutJsonAsync(url, body, headers);
+                result.Response = _response.Response;
+                result.Status = _response.StatusCode;
+                result.Success = _response.IsSuccessStatusCode;
+                result.Exception = _response.Exception;
+
+
+            }
+            catch (Exception ex)
+            {
+                result.Exception = ex;
+            }
+
+            return result;
+        }
+
+        private string PreAction(string url, ref Dictionary<string, string> headers, object requestBody, string saltkey)
+        {
+            var _body = requestBody == null ? "" : JsonConvert.SerializeObject(requestBody, GlobalConfig.JSONSERIALIZER_FORMAT);
+            headers.Add("Timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString());
+            string signature = GetSignature(GetUnencodeText(url, _body, headers["Timestamp"], headers["PartnerId"], saltkey));
+            headers.Add("Signature", signature);
+
+            return _body;
+        }
+
+
+        private string GetUnencodeText(string url, string body, string timestamp, string partnerId, string saltkey)
+        {
+
+            string tempText = url.Substring(url.IndexOf('?') + 1).ToLower();
+            tempText = tempText.StartsWith("http") ? string.Empty : tempText;
+            body = tempText + body;
+            string unencodeText = string.Format("{0}{1}{2}{3}", body, timestamp, partnerId, saltkey).ToLower();
+
+            return unencodeText;
+        }
+
+        private string GetSignature(string unencodeText)
+        {
+            if ((unencodeText == null) || (unencodeText.Length == 0))
+            {
+                return String.Empty;
+            }
+            unencodeText = unencodeText.ToLower();
+
+            MD5 md5 = new MD5CryptoServiceProvider();
+            byte[] textToHash = Encoding.UTF8.GetBytes(unencodeText);
+            byte[] result = md5.ComputeHash(textToHash);
+            return BitConverter.ToString(result).Replace("-", "").ToLower();
+        }
+
+    }
+
+    public class HttpResult
+    {
+        public int StatusCode { set; get; }
+
+        public bool Success { set; get; }
+
+        public HttpStatusCode Status { set; get; }
+
+        public Exception Exception { set; get; }
+
+        public string Response { set; get; }
+
+    }
+
+}

+ 18 - 0
EVCB_OCPP.WSServer.backup/SuperSocket.Command/ProcessCallCmd.cs

@@ -0,0 +1,18 @@
+using OCPPServer.Protocol;
+using SuperWebSocket.SubProtocol;
+
+namespace EVCB_OCPP.WSServer.SuperSocket.Command
+{
+    public class ProcessCallCmd : SubCommandBase<ClientData>
+    {
+        public override void ExecuteCommand(ClientData session, SubRequestInfo requestInfo)
+        {
+            session.ReceiveData(session, requestInfo.Body);
+        }
+
+        public override string Name
+        {
+            get { return "2"; }
+        }
+    }
+}

+ 18 - 0
EVCB_OCPP.WSServer.backup/SuperSocket.Command/ProcessCallErrorCmd.cs

@@ -0,0 +1,18 @@
+using OCPPServer.Protocol;
+using SuperWebSocket.SubProtocol;
+
+namespace EVCB_OCPP.WSServer.SuperSocket.Command
+{
+    public class ProcessCallErrorCmd : SubCommandBase<ClientData>
+    {
+        public override void ExecuteCommand(ClientData session, SubRequestInfo requestInfo)
+        {
+            session.ReceiveData(session, requestInfo.Body);
+        }
+
+        public override string Name
+        {
+            get { return "4"; }
+        }
+    }
+}

+ 18 - 0
EVCB_OCPP.WSServer.backup/SuperSocket.Command/ProcessCallResultCmd.cs

@@ -0,0 +1,18 @@
+using OCPPServer.Protocol;
+using SuperWebSocket.SubProtocol;
+
+namespace EVCB_OCPP.WSServer.SuperSocket.Command
+{
+    public class ProcessCallResultCmd : SubCommandBase<ClientData>
+    {
+        public override void ExecuteCommand(ClientData session, SubRequestInfo requestInfo)
+        {
+            session.ReceiveData(session, requestInfo.Body);
+        }
+
+        public override string Name
+        {
+            get { return "3"; }
+        }
+    }
+}

+ 128 - 0
EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/ClientData.cs

@@ -0,0 +1,128 @@
+
+using EVCB_OCPP.Packet.Messages.Basic;
+using EVCB_OCPP.WSServer.Dto;
+using SuperSocket.SocketBase;
+using SuperWebSocket;
+using System;
+using System.Collections.Generic;
+
+namespace OCPPServer.Protocol
+{
+    public class ClientData : WebSocketSession<ClientData>
+    { /// <summary>
+      /// 根據unique id來儲存.取出OCPP Request
+      /// </summary>
+        public Queue queue = new Queue();
+
+        public EVCB_OCPP20.Packet.Messages.Basic.Queue queue20 = new EVCB_OCPP20.Packet.Messages.Basic.Queue();
+
+        public bool IsPending { set; get; }
+        public bool IsCheckIn { set; get; }
+
+        public string ChargeBoxId { set; get; }
+
+        public Guid CustomerId { get; set; }
+
+        public string MachineId { set; get; }
+
+        public bool ISOCPP20 { set; get; }
+
+        public bool ResetSecurityProfile { set; get; }
+
+
+        public bool IsAC { set; get; }
+
+        #region Billing
+
+        public Dictionary<string,string> UserPrices { set; get; }
+
+        public Dictionary<string, string> UserDisplayPrices { set; get; }
+
+        public List<ChargingPrice> ChargingPrices { set; get; }
+
+        /// <summary>
+        /// 電樁顯示費率
+        /// </summary>
+        public string DisplayPrice { set; get; }
+
+        /// <summary>
+        /// 充電費率 以小時計費
+        /// </summary>
+        public decimal ChargingFeebyHour { set; get; }
+
+        /// <summary>
+        /// 停車費率 以小時計費
+        /// </summary>
+        public decimal ParkingFee { set; get; }
+
+        /// <summary>
+        /// 電樁是否計費
+        /// </summary>
+        public bool IsBilling { set; get; }
+
+        /// <summary>
+        /// 收費方式 1: 以度計費 2:以小時計費
+        /// </summary>
+        public int BillingMethod { set; get; }
+       
+
+        /// <summary>
+        /// 電樁適用幣別
+        /// </summary>
+        public string Currency { get; internal set; }
+
+        #endregion
+
+        public string CustomerName { get; set; }
+
+
+        public string StationName { set; get; }
+
+
+        public string StationLocation { set; get; }
+
+        public delegate void OCPPClientDataEventHandler<ClientData, String>(ClientData clientdata, String msg);
+
+        public event OCPPClientDataEventHandler<ClientData, String> m_ReceiveData;
+
+        public ClientData()
+        {
+            IsAC = true;
+            IsPending = false;
+            IsCheckIn = false;
+            ChargeBoxId = SessionID;
+            MachineId = SessionID;
+            UserPrices = new Dictionary<string, string>();
+            UserDisplayPrices = new Dictionary<string, string>();
+        }
+
+
+
+        /// <summary>
+        /// Sends the raw binary data to client.
+        /// </summary>
+        /// <param name="data">The data.</param>
+        /// <param name="offset">The offset.</param>
+        /// <param name="length">The length.</param>
+        public void SendRawData(byte[] data, int offset, int length)
+        {
+            base.Send(data, offset, length);
+        }
+
+        //receive data event trigger
+        public void ReceiveData(ClientData clientdata, string msg)
+        {
+            if (m_ReceiveData != null)
+                m_ReceiveData(clientdata, msg);
+        }
+
+        /// <summary>
+        /// Called when [session closed].
+        /// </summary>
+        /// <param name="reason">The reason.</param>
+        protected override void OnSessionClosed(CloseReason reason)
+        {
+        }
+
+    }
+}

+ 441 - 0
EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPLog.cs

@@ -0,0 +1,441 @@
+
+
+using SuperSocket.SocketBase.Logging;
+using System;
+
+namespace OCPPServer.SubProtocol
+{
+    public class OCPPLog : ILog
+    {
+        private NLog.ILogger m_Log;
+
+        public OCPPLog(string name)
+        {
+            m_Log = NLog.LogManager.GetCurrentClassLogger();
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is debug enabled.
+        /// </summary>
+        /// <value>
+        /// 	<c>true</c> if this instance is debug enabled; otherwise, <c>false</c>.
+        /// </value>
+        public bool IsDebugEnabled
+        {
+            get { return m_Log.IsDebugEnabled; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is error enabled.
+        /// </summary>
+        /// <value>
+        /// 	<c>true</c> if this instance is error enabled; otherwise, <c>false</c>.
+        /// </value>
+        public bool IsErrorEnabled
+        {
+            get { return m_Log.IsErrorEnabled; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is fatal enabled.
+        /// </summary>
+        /// <value>
+        /// 	<c>true</c> if this instance is fatal enabled; otherwise, <c>false</c>.
+        /// </value>
+        public bool IsFatalEnabled
+        {
+            get { return m_Log.IsFatalEnabled; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is info enabled.
+        /// </summary>
+        /// <value>
+        /// 	<c>true</c> if this instance is info enabled; otherwise, <c>false</c>.
+        /// </value>
+        public bool IsInfoEnabled
+        {
+            get { return m_Log.IsInfoEnabled; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is warn enabled.
+        /// </summary>
+        /// <value>
+        /// 	<c>true</c> if this instance is warn enabled; otherwise, <c>false</c>.
+        /// </value>
+        public bool IsWarnEnabled
+        {
+            get { return m_Log.IsWarnEnabled; }
+        }
+
+        /// <summary>
+        /// Logs the debug message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void Debug(object message)
+        {
+            m_Log.Debug(message);
+        }
+
+        /// <summary>
+        /// Logs the debug message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <param name="exception">The exception.</param>
+        public void Debug(object message, Exception exception)
+        {
+            //m_Log.Debug((System.IFormatProvider)message, exception);
+            m_Log.Debug(exception, message.ToString());
+        }
+
+        /// <summary>
+        /// Logs the debug message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        public void DebugFormat(string format, object arg0)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the debug message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void DebugFormat(string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the debug message.
+        /// </summary>
+        /// <param name="provider">The provider.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void DebugFormat(IFormatProvider provider, string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the debug message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        public void DebugFormat(string format, object arg0, object arg1)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the debug message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        /// <param name="arg2">The arg2.</param>
+        public void DebugFormat(string format, object arg0, object arg1, object arg2)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the error message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void Error(object message)
+        {
+            m_Log.Error(message);
+        }
+
+        /// <summary>
+        /// Logs the error message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <param name="exception">The exception.</param>
+        public void Error(object message, Exception exception)
+        {
+            //m_Log.Error((System.IFormatProvider)message, exception);
+            m_Log.Error(exception.ToString());
+        }
+
+        /// <summary>
+        /// Logs the error message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        public void ErrorFormat(string format, object arg0)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the error message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void ErrorFormat(string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the error message.
+        /// </summary>
+        /// <param name="provider">The provider.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void ErrorFormat(IFormatProvider provider, string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the error message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        public void ErrorFormat(string format, object arg0, object arg1)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the error message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        /// <param name="arg2">The arg2.</param>
+        public void ErrorFormat(string format, object arg0, object arg1, object arg2)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the fatal error message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void Fatal(object message)
+        {
+            m_Log.Fatal(message);
+        }
+
+        /// <summary>
+        /// Logs the fatal error message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <param name="exception">The exception.</param>
+        public void Fatal(object message, Exception exception)
+        {
+            m_Log.Fatal((System.IFormatProvider)message, exception);
+        }
+
+        /// <summary>
+        /// Logs the fatal error message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        public void FatalFormat(string format, object arg0)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the fatal error message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void FatalFormat(string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the fatal error message.
+        /// </summary>
+        /// <param name="provider">The provider.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void FatalFormat(IFormatProvider provider, string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the fatal error message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        public void FatalFormat(string format, object arg0, object arg1)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the fatal error message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        /// <param name="arg2">The arg2.</param>
+        public void FatalFormat(string format, object arg0, object arg1, object arg2)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the info message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void Info(object message)
+        {
+            m_Log.Info(message);
+        }
+
+        /// <summary>
+        /// Logs the info message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <param name="exception">The exception.</param>
+        public void Info(object message, Exception exception)
+        {
+            //m_Log.Info((System.IFormatProvider)message, exception);
+            m_Log.Info(exception, message.ToString());
+        }
+
+        /// <summary>
+        /// Logs the info message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        public void InfoFormat(string format, object arg0)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the info message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void InfoFormat(string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the info message.
+        /// </summary>
+        /// <param name="provider">The provider.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void InfoFormat(IFormatProvider provider, string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the info message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        public void InfoFormat(string format, object arg0, object arg1)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the info message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        /// <param name="arg2">The arg2.</param>
+        public void InfoFormat(string format, object arg0, object arg1, object arg2)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the warning message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void Warn(object message)
+        {
+            m_Log.Warn(message);
+        }
+
+        /// <summary>
+        /// Logs the warning message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <param name="exception">The exception.</param>
+        public void Warn(object message, Exception exception)
+        {
+            //m_Log.Warn((System.IFormatProvider)message, exception);
+            m_Log.Warn(exception, message.ToString());
+        }
+
+        /// <summary>
+        /// Logs the warning message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        public void WarnFormat(string format, object arg0)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the warning message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void WarnFormat(string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the warning message.
+        /// </summary>
+        /// <param name="provider">The provider.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="args">The args.</param>
+        public void WarnFormat(IFormatProvider provider, string format, params object[] args)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the warning message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        public void WarnFormat(string format, object arg0, object arg1)
+        {
+
+        }
+
+        /// <summary>
+        /// Logs the warning message.
+        /// </summary>
+        /// <param name="format">The format.</param>
+        /// <param name="arg0">The arg0.</param>
+        /// <param name="arg1">The arg1.</param>
+        /// <param name="arg2">The arg2.</param>
+        public void WarnFormat(string format, object arg0, object arg1, object arg2)
+        {
+
+        }
+    }
+}

+ 31 - 0
EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPLogFactory.cs

@@ -0,0 +1,31 @@
+using SuperSocket.SocketBase.Logging;
+using System.Collections.Generic;
+
+namespace OCPPServer.SubProtocol
+{
+    /// <summary>
+    /// OCPP log factory
+    /// </summary>
+    public class OCPPLogFactory : LogFactoryBase
+    {
+        public OCPPLogFactory() : this("NLog.config")
+        {
+
+        }
+
+        public OCPPLogFactory(string log4netConfig)
+            : base(log4netConfig)
+        {
+            List<string> configlist = new List<string>();
+            configlist.Add(ConfigFile);
+            NLog.Config.XmlLoggingConfiguration.SetCandidateConfigFilePaths(configlist);
+        }
+
+        public override SuperSocket.SocketBase.Logging.ILog GetLog(string name)
+        {
+
+            return new OCPPLog(name);
+        }
+    }
+
+}

+ 0 - 0
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPSubCommandParser.cs → EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPSubCommandParser.cs


+ 322 - 0
EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPSubProtocol.cs

@@ -0,0 +1,322 @@
+using OCPPServer.Protocol;
+using SuperSocket.Common;
+using SuperSocket.SocketBase;
+using SuperSocket.SocketBase.Logging;
+using SuperSocket.SocketBase.Protocol;
+using SuperWebSocket;
+using SuperWebSocket.Config;
+using SuperWebSocket.SubProtocol;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace OCPPServer.SubProtocol
+{
+    public class OCPPSubProtocol : OCPPSubProtocol<ClientData>
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol"/> class.
+        /// </summary>
+        public OCPPSubProtocol()
+            : base(Assembly.GetCallingAssembly())
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol"/> class.
+        /// </summary>
+        /// <param name="name">The sub protocol name.</param>
+        public OCPPSubProtocol(string name)
+            : base(name, Assembly.GetCallingAssembly())
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol"/> class.
+        /// </summary>
+        /// <param name="commandAssembly">The command assembly.</param>
+        public OCPPSubProtocol(Assembly commandAssembly)
+            : base(commandAssembly)
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OCPPSubProtocol"/> class.
+        /// </summary>
+        /// <param name="commandAssemblies">The command assemblies.</param>
+        public OCPPSubProtocol(IEnumerable<Assembly> commandAssemblies)
+            : base(commandAssemblies)
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OCPPSubProtocol"/> class.
+        /// </summary>
+        /// <param name="name">The sub protocol name.</param>
+        /// <param name="commandAssembly">The command assembly.</param>
+        public OCPPSubProtocol(string name, Assembly commandAssembly)
+            : base(name, commandAssembly)
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OCPPSubProtocol"/> class.
+        /// </summary>
+        /// <param name="name">The sub protocol name.</param>
+        /// <param name="commandAssemblies">The command assemblies.</param>
+        public OCPPSubProtocol(string name, IEnumerable<Assembly> commandAssemblies)
+            : base(name, commandAssemblies)
+        {
+
+        }
+
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OCPPSubProtocol"/> class.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="commandAssemblies">The command assemblies.</param>
+        /// <param name="requestInfoParser">The request info parser.</param>
+        public OCPPSubProtocol(string name, IEnumerable<Assembly> commandAssemblies, IRequestInfoParser<SubRequestInfo> requestInfoParser)
+            : base(name, commandAssemblies, requestInfoParser)
+        {
+
+        }
+
+        public ILog Getmlog()
+        {
+            return getlog();
+        }
+
+    }
+
+    public class OCPPSubProtocol<TWebSocketSession> : SubProtocolBase<TWebSocketSession>
+       where TWebSocketSession : WebSocketSession<TWebSocketSession>, new()
+    {
+        /// <summary>
+        /// Default basic sub protocol name
+        /// </summary>
+        public const string DefaultName = "ocpp1.6";//"OCPP1.6";
+
+        private List<Assembly> m_CommandAssemblies = new List<Assembly>();
+
+        private Dictionary<string, ISubCommand<TWebSocketSession>> m_CommandDict;
+
+        private ILog m_Logger;
+
+        private SubCommandFilterAttribute[] m_GlobalFilters;
+
+        internal static BasicSubProtocol<TWebSocketSession> CreateDefaultSubProtocol()
+        {
+            var commandAssembly = typeof(TWebSocketSession).Assembly;
+
+            if (commandAssembly == Assembly.GetExecutingAssembly())
+                commandAssembly = Assembly.GetEntryAssembly();
+
+            return new BasicSubProtocol<TWebSocketSession>(DefaultName, commandAssembly);
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol&lt;TWebSocketSession&gt;"/> class with the calling aseembly as command assembly
+        /// </summary>
+        public OCPPSubProtocol()
+            : this(DefaultName, Assembly.GetCallingAssembly())
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol&lt;TWebSocketSession&gt;"/> class with the calling aseembly as command assembly
+        /// </summary>
+        /// <param name="name">The sub protocol name.</param>
+        public OCPPSubProtocol(string name)
+            : this(name, Assembly.GetCallingAssembly())
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol&lt;TWebSocketSession&gt;"/> class with command assemblies
+        /// </summary>
+        /// <param name="commandAssemblies">The command assemblies.</param>
+        public OCPPSubProtocol(IEnumerable<Assembly> commandAssemblies)
+            : this(DefaultName, commandAssemblies, new OCPPSubCommandParser())
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol&lt;TWebSocketSession&gt;"/> class with single command assembly.
+        /// </summary>
+        /// <param name="commandAssembly">The command assembly.</param>
+        public OCPPSubProtocol(Assembly commandAssembly)
+            : this(DefaultName, new List<Assembly> { commandAssembly }, new OCPPSubCommandParser())
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol&lt;TWebSocketSession&gt;"/> class with name and single command assembly.
+        /// </summary>
+        /// <param name="name">The sub protocol name.</param>
+        /// <param name="commandAssembly">The command assembly.</param>
+        public OCPPSubProtocol(string name, Assembly commandAssembly)
+            : this(name, new List<Assembly> { commandAssembly }, new OCPPSubCommandParser())
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol&lt;TWebSocketSession&gt;"/> class with name and command assemblies.
+        /// </summary>
+        /// <param name="name">The sub protocol name.</param>
+        /// <param name="commandAssemblies">The command assemblies.</param>
+        public OCPPSubProtocol(string name, IEnumerable<Assembly> commandAssemblies)
+            : this(name, commandAssemblies, new OCPPSubCommandParser())
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BasicSubProtocol&lt;TWebSocketSession&gt;"/> class.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="commandAssemblies">The command assemblies.</param>
+        /// <param name="requestInfoParser">The request info parser.</param>
+        public OCPPSubProtocol(string name, IEnumerable<Assembly> commandAssemblies, IRequestInfoParser<SubRequestInfo> requestInfoParser)
+            : base(name)
+        {
+            //The items in commandAssemblies may be null, so filter here
+            m_CommandAssemblies.AddRange(commandAssemblies.Where(a => a != null));
+            SubRequestParser = requestInfoParser;
+        }
+
+
+
+        #region ISubProtocol Members
+
+        private void DiscoverCommands()
+        {
+            var subCommands = new List<ISubCommand<TWebSocketSession>>();
+
+            foreach (var assembly in m_CommandAssemblies)
+            {
+                subCommands.AddRange(assembly.GetImplementedObjectsByInterface<ISubCommand<TWebSocketSession>>());
+            }
+
+#if DEBUG
+            var cmdbuilder = new StringBuilder();
+            cmdbuilder.AppendLine(string.Format("SubProtocol {0} found the commands below:", this.Name));
+
+            foreach (var c in subCommands)
+            {
+                cmdbuilder.AppendLine(c.Name);
+            }
+
+
+            m_Logger.Debug(cmdbuilder.ToString());
+#endif
+
+            m_CommandDict = new Dictionary<string, ISubCommand<TWebSocketSession>>(subCommands.Count, StringComparer.OrdinalIgnoreCase);
+
+            subCommands.ForEach(c =>
+            {
+                var fc = c as ISubCommandFilterLoader;
+
+                if (fc != null)
+                    fc.LoadSubCommandFilters(m_GlobalFilters);
+
+                m_CommandDict.Add(c.Name, c);
+            }
+                );
+        }
+
+
+        private bool ResolveCommmandAssembly(string definition)
+        {
+            try
+            {
+                var assemblies = AssemblyUtil.GetAssembliesFromString(definition);
+
+                if (assemblies.Any())
+                    m_CommandAssemblies.AddRange(assemblies);
+
+                return true;
+            }
+            catch (Exception e)
+            {
+                m_Logger.Error(e);
+                return false;
+            }
+        }
+
+        public ILog getlog()
+        {
+            return m_Logger;
+        }
+
+        /// <summary>
+        /// Tries get command from the sub protocol's command inventory.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="command">The command.</param>
+        /// <returns></returns>
+        public override bool TryGetCommand(string name, out ISubCommand<TWebSocketSession> command)
+        {
+            return m_CommandDict.TryGetValue(name, out command);
+        }
+
+
+
+        public override bool Initialize(IAppServer appServer, SubProtocolConfig protocolConfig, ILog logger)
+        {
+            m_Logger = logger;
+
+            var config = appServer.Config;
+
+            m_GlobalFilters = appServer.GetType()
+                    .GetCustomAttributes(true)
+                    .OfType<SubCommandFilterAttribute>()
+                    .Where(a => string.IsNullOrEmpty(a.SubProtocol) || Name.Equals(a.SubProtocol, StringComparison.OrdinalIgnoreCase)).ToArray();
+
+            if (Name.Equals(DefaultName, StringComparison.OrdinalIgnoreCase))
+            {
+                var commandAssembly = config.Options.GetValue("commandAssembly");
+
+                if (!string.IsNullOrEmpty(commandAssembly))
+                {
+                    if (!ResolveCommmandAssembly(commandAssembly))
+                        return false;
+                }
+            }
+
+            if (protocolConfig != null && protocolConfig.Commands != null)
+            {
+                foreach (var commandConfig in protocolConfig.Commands)
+                {
+                    var assembly = commandConfig.Options.GetValue("assembly");
+
+                    if (!string.IsNullOrEmpty(assembly))
+                    {
+                        if (!ResolveCommmandAssembly(assembly))
+                            return false;
+                    }
+                }
+            }
+
+            //Always discover commands
+            DiscoverCommands();
+
+            return true;
+        }
+
+        #endregion
+    }
+}

+ 215 - 0
EVCB_OCPP.WSServer.backup/SuperSocket.Protocol/OCPPWSServer.cs

@@ -0,0 +1,215 @@
+
+using EVCB_OCPP.Domain;
+using NLog;
+using OCPPPackage.Profiles;
+using SuperWebSocket;
+using SuperWebSocket.SubProtocol;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+
+namespace OCPPServer.Protocol
+{
+    public class OCPPWSServer : WebSocketServer<ClientData>
+    {
+
+        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        /// <summary>
+        /// 可允許連線Clinet數
+        /// </summary>
+        public int connectNum { get; set; }
+
+        /// <summary>
+        /// 是否限制連線Clinet數
+        /// </summary>
+        public bool beConnectLimit { get; set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
+        /// </summary>
+        /// <param name="subProtocols">The sub protocols.</param>
+        public OCPPWSServer(IEnumerable<ISubProtocol<ClientData>> subProtocols)
+            : base(subProtocols)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
+        /// </summary>
+        /// <param name="subProtocol">The sub protocol.</param>
+        public OCPPWSServer(ISubProtocol<ClientData> subProtocol)
+            : base(subProtocol)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
+        /// </summary>
+        public OCPPWSServer()
+            : base(new List<ISubProtocol<ClientData>>())
+        {
+
+        }
+
+        protected override bool ValidateClientCertificate(ClientData session, object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
+        {
+            //  Console.WriteLine(string.Format("{0} :{1}", session.ChargeBoxId + " ValidateClientCertificate", sslPolicyErrors));
+            return true;
+            // return base.ValidateClientCertificate(session, sender, certificate, chain, sslPolicyErrors);
+        }
+
+        protected override bool ValidateHandshake(ClientData session, string origin)
+        {
+            session.ISOCPP20 = session.SecWebSocketProtocol.ToLower().Contains("ocpp2.0");
+
+            int securityProfile = 0;
+            string authorizationKey = string.Empty;
+            if (string.IsNullOrEmpty(session.Path))
+            {
+                logger.Warn("===========================================");
+                logger.Warn("session.Path EMPTY");
+                logger.Warn("===========================================");
+            }
+
+            string[] words = session.Path.Split('/');
+            session.ChargeBoxId = words.Last();
+
+            if (ConfigurationManager.AppSettings["MaintainMode"] == "1")
+            {
+                session.ChargeBoxId = session.ChargeBoxId + "_2";
+            }
+
+            logger.Info(string.Format("ValidateHandshake: {0}", session.Path));
+            bool isExistedSN = false;
+            bool authorizated = false;
+            using (var db = new MainDBContext())
+            {
+                var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).FirstOrDefault();
+                session.CustomerName = machine == null ? "Unknown" : db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefault();
+                session.CustomerId = machine == null ? Guid.Empty : machine.CustomerId;
+                session.MachineId = machine == null ? String.Empty : machine.Id;
+                isExistedSN = machine == null ? false : true;
+
+                if (!isExistedSN)
+                {
+                    StringBuilder responseBuilder = new StringBuilder();
+
+                    responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
+                    (int)HttpStatusCode.NotFound, @"Not Found");
+                  
+                    responseBuilder.AppendWithCrCf();
+                    string sb = responseBuilder.ToString();
+                    byte[] data = Encoding.UTF8.GetBytes(sb);
+                    ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
+
+                    logger.Info(sb);
+                    return false;
+                }
+
+                var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile)
+                                  .Select(x => x.ConfigureSetting).FirstOrDefault();
+                int.TryParse(configVaule, out securityProfile);
+
+                if (session.ISOCPP20)
+                {
+                    // 1.6 server only support change server  function
+                    securityProfile = 0;
+                }
+            }
+            if (securityProfile == 3 && session.UriScheme == "ws")
+            {
+                StringBuilder responseBuilder = new StringBuilder();
+
+                responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
+                (int)HttpStatusCode.Unauthorized, @"Unauthorized");
+
+                responseBuilder.AppendWithCrCf();
+                string sb = responseBuilder.ToString();
+                byte[] data = Encoding.UTF8.GetBytes(sb);
+
+                ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
+                logger.Info(sb);
+                return false;
+            }
+
+            if ((securityProfile == 1 || securityProfile == 2))
+            {
+                if (securityProfile == 2 && session.UriScheme == "ws")
+                {
+                    authorizated = false;
+                }
+
+                if (session.Items.ContainsKey("Authorization") || session.Items.ContainsKey("authorization"))
+                {
+
+                    using (var db = new MainDBContext())
+                    {
+
+                        authorizationKey = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey)
+                                          .Select(x => x.ConfigureSetting).FirstOrDefault();
+
+
+                        if (session.ISOCPP20)
+                        {
+                            // 1.6 server only support change server  function
+                            securityProfile = 0;
+                        }
+                    }
+                    logger.Info("***********Authorization   ");
+
+                    if (!string.IsNullOrEmpty(authorizationKey))
+                    {
+                        string base64Encoded = session.Items.ContainsKey("Authorization") ? session.Items["Authorization"].ToString().Replace("Basic ", "") : session.Items["authorization"].ToString().Replace("Basic ", "");
+                        byte[] data = Convert.FromBase64String(base64Encoded);
+                        string[] base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(data).Split(':');
+                        logger.Info("***********Authorization   " + System.Text.ASCIIEncoding.ASCII.GetString(data));
+                        if (base64Decoded.Count() == 2 && base64Decoded[0] == session.ChargeBoxId && base64Decoded[1] == authorizationKey)
+                        {
+                            authorizated = true;
+                        }
+                    }
+
+
+
+
+
+                }
+                else
+                {
+                    authorizated = true;
+
+                }
+
+
+
+                if (!authorizated)
+                {
+                    StringBuilder responseBuilder = new StringBuilder();
+
+                    responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
+                    (int)HttpStatusCode.Unauthorized, @"Unauthorized");
+
+                    responseBuilder.AppendWithCrCf();
+                    string sb = responseBuilder.ToString();
+                    byte[] data = Encoding.UTF8.GetBytes(sb);
+
+                    ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
+                    logger.Info(sb);
+                    return false;
+                }
+            }
+
+
+         
+
+
+
+            return true;
+        }
+    }
+}

+ 0 - 0
EVCB_OCPP.WSServer/packages.config → EVCB_OCPP.WSServer.backup/packages.config


+ 1 - 0
EVCB_OCPP.WSServer.backup/upgrade.backup

@@ -0,0 +1 @@
+Backup created at 1672800646 (2023/1/4 上午 02:50:46 +00:00)

BIN
EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Domain.dll


BIN
EVCB_OCPP.WSServer/DLL/EVCB_OCPP.Packet.dll


+ 29 - 0
EVCB_OCPP.WSServer/Dockerfile

@@ -0,0 +1,29 @@
+#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/aspnet:7.0 AS base
+RUN sed -i 's/TLSv1.2/TLSv1/g' /etc/ssl/openssl.cnf
+RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
+EXPOSE 80
+EXPOSE 443
+EXPOSE 54088
+WORKDIR /app
+
+FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
+WORKDIR /src
+COPY ["EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj", "EVCB_OCPP.WSServer/"]
+COPY ["SuperWebSocket/SuperWebSocket.csproj", "SuperWebSocket/"]
+COPY ["SocketBase/SuperSocket.SocketBase.csproj", "SocketBase/"]
+COPY ["SocketCommon/SuperSocket.Common.csproj", "SocketCommon/"]
+COPY ["SocketEngine/SuperSocket.SocketEngine.csproj", "SocketEngine/"]
+RUN dotnet restore "EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+COPY . .
+WORKDIR "/src/EVCB_OCPP.WSServer"
+RUN dotnet build "EVCB_OCPP.WSServer.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "EVCB_OCPP.WSServer.csproj" -c Release -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "EVCB_OCPP.WSServer.dll"]

+ 30 - 195
EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj

@@ -1,17 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{DE0C1E9A-1EEE-42CC-8A91-73BF9056A7E7}</ProjectGuid>
+    <TargetFramework>net7.0</TargetFramework>
     <OutputType>Exe</OutputType>
-    <RootNamespace>EVCB_OCPP.WSServer</RootNamespace>
-    <AssemblyName>EVCB_OCPP.WSServer</AssemblyName>
-    <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
-    <Deterministic>true</Deterministic>
     <IsWebBootstrapper>false</IsWebBootstrapper>
     <PublishUrl>publish\</PublishUrl>
     <Install>true</Install>
@@ -27,38 +17,11 @@
     <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
     <UseApplicationTrust>false</UseApplicationTrust>
     <BootstrapperEnabled>true</BootstrapperEnabled>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <DockerfileRunArguments>-p 54088:54088 -p 80:80</DockerfileRunArguments>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Dapper, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\Dapper.2.0.30\lib\net461\Dapper.dll</HintPath>
-    </Reference>
-    <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
-      <HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
-    </Reference>
-    <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
-      <HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
-    </Reference>
-    <Reference Include="EVCB_OCPP.Domain, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
+    <Reference Include="EVCB_OCPP.Domain">
       <HintPath>DLL\EVCB_OCPP.Domain.dll</HintPath>
     </Reference>
     <Reference Include="EVCB_OCPP.Packet, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
@@ -69,165 +32,16 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>DLL\EVCB_OCPP20.Packet.dll</HintPath>
     </Reference>
-    <Reference Include="log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
-      <HintPath>..\packages\log4net.2.0.3\lib\net40-full\log4net.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Configuration.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration.Binder, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.DependencyInjection, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.3.1.3\lib\net461\Microsoft.Extensions.DependencyInjection.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.3\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Http, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Http.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Http.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Logging, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Logging.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Options, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Options.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Primitives, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Primitives.3.1.3\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <HintPath>..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
-    <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
-      <HintPath>..\packages\NLog.4.6.6\lib\net45\NLog.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
-    </Reference>
-    <Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
-    </Reference>
-    <Reference Include="System.ComponentModel.DataAnnotations" />
-    <Reference Include="System.Configuration" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.IO.Compression" />
-    <Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Numerics" />
-    <Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Runtime.Serialization" />
-    <Reference Include="System.ServiceModel" />
-    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Transactions" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Dto\ChargingPrice.cs" />
-    <Compile Include="Dto\ErrorDetails.cs" />
-    <Compile Include="Dto\IdTokenInfo.cs" />
-    <Compile Include="Dto\ID_GetTxUserInfo.cs" />
-    <Compile Include="Dto\StationFee.cs" />
-    <Compile Include="Dto\TCCWeatherDto.cs" />
-    <Compile Include="Dto\TransactionEnergy.cs" />
-    <Compile Include="Dto\TCCStationInfoDto.cs" />
-    <Compile Include="Message\OCPP16MessageHandler.cs" />
-    <Compile Include="Message\OCPP20MessageHandler.cs" />
-    <Compile Include="Message\SecurityProfileHandler.cs" />
-    <Compile Include="Service\BusinessServiceFactory.cs" />
-    <Compile Include="Service\HttpClientService.cs" />
-    <Compile Include="Service\LoadingBalanceService.cs" />
-    <Compile Include="Service\LocalBusinessService.cs" />
-    <Compile Include="Service\OuterBusinessService.cs" />
-    <Compile Include="Dto\ConnectorErrorStauts.cs" />
-    <Compile Include="GlobalConfig.cs" />
-    <Compile Include="Helper\Convertor.cs" />
-    <Compile Include="Message\BasicMessageHandler.cs" />
-    <Compile Include="Message\CoreProfileHandler.cs" />
-    <Compile Include="Message\FirmwareManagementProfileHandler.cs" />
-    <Compile Include="Message\LocalAuthListManagementProfileHandler.cs" />
-    <Compile Include="Message\MessageResult.cs" />
-    <Compile Include="Message\NeedConfirmMessage.cs" />
-    <Compile Include="Message\RemoteTriggerHandler.cs" />
-    <Compile Include="Message\ReservationProfileHandler.cs" />
-    <Compile Include="Message\SmartChargingProfileHandler.cs" />
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="ProtalServer.cs" />
-    <Compile Include="Service\OuterHttpClient.cs" />
-    <Compile Include="SuperSocket.Command\ProcessCallCmd.cs" />
-    <Compile Include="SuperSocket.Command\ProcessCallErrorCmd.cs" />
-    <Compile Include="SuperSocket.Command\ProcessCallResultCmd.cs" />
-    <Compile Include="SuperSocket.Protocol\ClientData.cs" />
-    <Compile Include="SuperSocket.Protocol\OCPPLog.cs" />
-    <Compile Include="SuperSocket.Protocol\OCPPLogFactory.cs" />
-    <Compile Include="SuperSocket.Protocol\OCPPSubCommandParser.cs" />
-    <Compile Include="SuperSocket.Protocol\OCPPSubProtocol.cs" />
-    <Compile Include="SuperSocket.Protocol\OCPPWSServer.cs" />
   </ItemGroup>
   <ItemGroup>
-    <None Include="App.config">
-      <SubType>Designer</SubType>
-    </None>
-    <Content Include="DLL\EVCB_OCPP20.Packet.dll" />
-    <Content Include="DLL\SuperSocket.Common.dll" />
-    <Content Include="DLL\SuperSocket.SocketBase.dll" />
-    <Content Include="DLL\SuperSocket.SocketEngine.dll" />
-    <Content Include="DLL\SuperWebSocket.dll" />
-    <Content Include="NLog.config">
+    <Content Include="appsettings.json">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-      <SubType>Designer</SubType>
     </Content>
-    <None Include="NLog.xsd">
-      <SubType>Designer</SubType>
-    </None>
-    <None Include="packages.config" />
+    <Content Include="DLL\EVCB_OCPP20.Packet.dll" />
   </ItemGroup>
   <ItemGroup>
-    <Content Include="DLL\EVCB_OCPP.Domain.dll" />
     <Content Include="DLL\EVCB_OCPP.Packet.dll" />
   </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\SocketBase\SuperSocket.SocketBase.Net40.csproj">
-      <Project>{40b77789-ea11-4c05-8f52-86711d7bcaaf}</Project>
-      <Name>SuperSocket.SocketBase.Net40</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\SocketCommon\SuperSocket.Common.Net40.csproj">
-      <Project>{a24f4d38-ba9c-4fd6-95b7-4980de36131a}</Project>
-      <Name>SuperSocket.Common.Net40</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\SocketEngine\SuperSocket.SocketEngine.Net40.csproj">
-      <Project>{153fef72-191c-43d9-be71-2b351c7ac760}</Project>
-      <Name>SuperSocket.SocketEngine.Net40</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\SuperWebSocket\SuperWebSocket.NET45.csproj">
-      <Project>{2dc79e40-bb70-4f6a-b378-905f2fbc6e97}</Project>
-      <Name>SuperWebSocket.NET45</Name>
-    </ProjectReference>
-  </ItemGroup>
   <ItemGroup>
     <BootstrapperPackage Include=".NETFramework,Version=v4.7.1">
       <Visible>False</Visible>
@@ -240,8 +54,29 @@
       <Install>false</Install>
     </BootstrapperPackage>
   </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <PackageReference Include="Dapper" Version="2.0.123" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.2" />
+    <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
+    <PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
+    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
+    <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
+    <PackageReference Include="NLog" Version="5.1.1" />
+    <PackageReference Include="NLog.Web.AspNetCore" Version="5.2.1" />
+    <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
+    <PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
+    <PackageReference Include="System.ServiceModel.Federation" Version="4.10.0" />
+    <PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.355802">
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
+    <PackageReference Include="EntityFramework" Version="6.4.4" />
+    <PackageReference Include="log4net" Version="2.0.15" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\SuperWebSocket\SuperWebSocket.csproj" />
+  </ItemGroup>
   <PropertyGroup>
-    <PreBuildEvent>GitVersion.exe $(ProjectDir) /updateassemblyinfo</PreBuildEvent>
+    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
   </PropertyGroup>
 </Project>

+ 7 - 27
EVCB_OCPP.WSServer/GlobalConfig.cs

@@ -1,4 +1,5 @@
-using Newtonsoft.Json;
+using Microsoft.Extensions.Configuration;
+using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
 using System.Configuration;
@@ -9,8 +10,6 @@ namespace EVCB_OCPP.WSServer
     {
         public static List<string> ConfigKeys = new List<string>()
         {
-            "WSPort",
-            "WSSPort",
             "OCPP20_WSUrl",
             "OCPP20_WSSUrl"
         };
@@ -42,18 +41,15 @@ namespace EVCB_OCPP.WSServer
         /// <summary>
         ///WS Port
         /// </summary>
-        private static int WS_Port = 2012;
+        private static int WS_Port = 80;
 
 
         /// <summary>
         ///WSS Port
         /// </summary>
-        private static int WSS_Port = 2013;
+        private static int WSS_Port = 443;
 
-        /// <summary>
-        /// Load setting from app.config 
-        /// </summary>
-        public static bool LoadAPPConfig()
+        public static bool LoadAPPConfig(IConfiguration configuration)
         {
             bool result = false;
             string key = string.Empty;
@@ -65,30 +61,16 @@ namespace EVCB_OCPP.WSServer
                     key = ConfigKeys[i];
                     switch (key)
                     {
-                        case "WSPort":// convert to int type                       
-                            {
-                                var value = ConfigurationManager.AppSettings[key];
-
-                                WS_Port = Convert.ToInt32(value);
-                            }
-                            break;
-                        case "WSSPort":
-                            {
-                                var value = ConfigurationManager.AppSettings[key];
-
-                                WSS_Port = Convert.ToInt32(value);
-                            }
-                            break;
                         case "OCPP20_WSUrl":// convert to int type                       
                             {
-                                var value = ConfigurationManager.AppSettings[key];
+                                var value = configuration[key];
 
                                 OCPP20_WSUrl = value;
                             }
                             break;
                         case "OCPP20_WSSUrl":// convert to int type                       
                             {
-                                var value = ConfigurationManager.AppSettings[key];
+                                var value = configuration[key];
 
                                 OCPP20_WSSUrl = value;
                             }
@@ -110,8 +92,6 @@ namespace EVCB_OCPP.WSServer
             return result;
         }
 
-
-
         public static int GetWS_Port()
         {
             return WS_Port;

+ 9 - 8
EVCB_OCPP.WSServer/Message/BasicMessageHandler.cs

@@ -1,8 +1,9 @@
 using EVCB_OCPP.Packet.Features;
 using EVCB_OCPP.Packet.Messages;
+using Microsoft.Extensions.Logging;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Serialization;
-using NLog;
+
 using OCPPServer.Protocol;
 
 
@@ -15,7 +16,7 @@ namespace EVCB_OCPP.WSServer.Message
     /// </summary>
     internal class BasicMessageHandler
     {
-        static protected ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        static protected ILogger logger;
 
         #region 傳送 or 解析訊息需要欄位
         private const int INDEX_MESSAGEID = 0;
@@ -82,7 +83,7 @@ namespace EVCB_OCPP.WSServer.Message
             }
             else
             {
-                logger.Error(string.Format("confirmation is null  or InVaild in GenerateConfirmation Method"), "Warning");
+                logger.LogError(string.Format("confirmation is null  or InVaild in GenerateConfirmation Method"), "Warning");
             }
             return msg;
         }
@@ -96,7 +97,7 @@ namespace EVCB_OCPP.WSServer.Message
             }
             else
             {
-                logger.Error(string.Format("confirmation is null  or InVaild in GenerateConfirmation Method"), "Warning");
+                logger.LogError(string.Format("confirmation is null  or InVaild in GenerateConfirmation Method"), "Warning");
             }
             return msg;
         }
@@ -115,17 +116,17 @@ namespace EVCB_OCPP.WSServer.Message
                 {
                     if(!request.Validate())
                     {
-                        logger.Error("!Validate", "Warning");
+                        logger.LogError("!Validate", "Warning");
                     }
 
                     if (request == null)
                     {
-                        logger.Error("!NULL", "Warning");
+                        logger.LogError("!NULL", "Warning");
                     }
 
                 }
 
-                logger.Error(string.Format("confirmation is null  or InVaild in GenerateRequest Method "+ action), "Warning");
+                logger.LogError(string.Format("confirmation is null  or InVaild in GenerateRequest Method "+ action), "Warning");
             }
             return msg;
         }
@@ -140,7 +141,7 @@ namespace EVCB_OCPP.WSServer.Message
             }
             else
             {
-                logger.Error(string.Format("confirmation is null  or InVaild in GenerateRequest Method"), "Warning");
+                logger.LogError(string.Format("confirmation is null  or InVaild in GenerateRequest Method"), "Warning");
             }
             return msg;
         }

+ 85 - 68
EVCB_OCPP.WSServer/Message/CoreProfileHandler.cs

@@ -7,17 +7,21 @@ using EVCB_OCPP.Packet.Messages.Core;
 using EVCB_OCPP.Packet.Messages.SubTypes;
 using EVCB_OCPP.WSServer.Dto;
 using EVCB_OCPP.WSServer.Service;
+using Microsoft.Data.SqlClient;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using MongoDB.Driver.Core.Servers;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
-using NLog;
+
 using OCPPPackage.Profiles;
 using OCPPServer.Protocol;
 using System;
 using System.Collections.Generic;
 using System.Configuration;
 using System.Data;
-using System.Data.Entity;
-using System.Data.SqlClient;
 using System.Diagnostics;
 using System.Globalization;
 using System.Linq;
@@ -65,10 +69,27 @@ namespace EVCB_OCPP.WSServer.Message
 
     internal partial class ProfileHandler
     {
-        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
-        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+        static private ILogger logger;
+        private readonly string webConnectionString;// = ConfigurationManager.ConnectionStrings[].ConnectionString;
+        private readonly IDbContextFactory<MainDBContext> maindbContextFactory;
+        private readonly IDbContextFactory<MeterValueDBContext> metervaluedbContextFactory;
+        private readonly IServiceProvider serviceProvider;
         private OuterHttpClient httpClient = new OuterHttpClient();
-     
+
+        public ProfileHandler(
+            IConfiguration configuration,
+            IDbContextFactory<MainDBContext> maindbContextFactory, 
+            IDbContextFactory<MeterValueDBContext> metervaluedbContextFactory,
+            IServiceProvider serviceProvider)
+        {
+            webConnectionString = configuration.GetConnectionString("WebDBContext");
+            logger = serviceProvider.GetService<ILogger<ProfileHandler>>();
+
+            this.maindbContextFactory = maindbContextFactory;
+            this.serviceProvider = serviceProvider;
+            this.metervaluedbContextFactory = metervaluedbContextFactory;
+        }
+
         async internal Task<MessageResult> ExecuteCoreRequest(Actions action, ClientData session, IRequest request)
         {
             Stopwatch watch = new Stopwatch();
@@ -111,7 +132,7 @@ namespace EVCB_OCPP.WSServer.Message
 
                                         }, report, GlobalConfig.TCC_SALTKEY);
 
-                                    logger.Debug(JsonConvert.SerializeObject(response));
+                                    logger.LogDebug(JsonConvert.SerializeObject(response));
                                 }
 
 
@@ -149,9 +170,9 @@ namespace EVCB_OCPP.WSServer.Message
                             {
                                 JObject jo = JObject.Parse(_request.data);
 
-                                logger.Debug(string.Format("{0}\r\n{1}\r\n{2}", jo["txId"].Value<int>(), jo["dataString"].Value<string>(), jo["publicKey"].Value<string>()));
+                                logger.LogDebug("{0}\r\n{1}\r\n{2}", jo["txId"].Value<int>(), jo["dataString"].Value<string>(), jo["publicKey"].Value<string>());
 
-                                using (var db = new MainDBContext())
+                                using (var db = await maindbContextFactory.CreateDbContextAsync())
                                 {
                                     db.OCMF.Add(new OCMF()
                                     {
@@ -175,7 +196,7 @@ namespace EVCB_OCPP.WSServer.Message
                         {
                             BootNotificationRequest _request = request as BootNotificationRequest;
                             int heartbeat_interval = GlobalConfig.GetHEARTBEAT_INTERVAL();
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var _machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
                                 _machine.ChargeBoxSerialNumber = string.IsNullOrEmpty(_request.chargeBoxSerialNumber) ? string.Empty : _request.chargeBoxSerialNumber;
@@ -193,7 +214,7 @@ namespace EVCB_OCPP.WSServer.Message
 
 
 
-                                var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.HeartbeatInterval)
+                                var configVaule = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.HeartbeatInterval)
                                     .Select(x => x.ConfigureSetting).FirstOrDefault();
 
                                 if (configVaule != null)
@@ -213,7 +234,7 @@ namespace EVCB_OCPP.WSServer.Message
                             //只保留最新上報狀況
                             StatusNotificationRequest _request = request as StatusNotificationRequest;
                             int preStatus = 0;
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var _oldStatus = db.ConnectorStatus.Where(x => x.ChargeBoxId == session.ChargeBoxId
                               && x.ConnectorId == _request.connectorId).AsNoTracking().FirstOrDefault();
@@ -224,8 +245,8 @@ namespace EVCB_OCPP.WSServer.Message
 
                                     preStatus = _oldStatus.Status;
 
-                                    db.Configuration.AutoDetectChangesEnabled = false;
-                                    db.Configuration.ValidateOnSaveEnabled = false;
+                                    //db.Configuration.AutoDetectChangesEnabled = false;
+                                    //db.Configuration.ValidateOnSaveEnabled = false;
                                     db.ConnectorStatus.Attach(_oldStatus);
 
 
@@ -285,7 +306,8 @@ namespace EVCB_OCPP.WSServer.Message
 
                             if (_request.status == Packet.Messages.SubTypes.ChargePointStatus.Faulted)
                             {
-                                var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+                                //var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+                                var businessService = await serviceProvider.GetService<BusinessServiceFactory>().CreateBusinessService(session.CustomerId.ToString());
                                 var notification = businessService.NotifyFaultStatus(new ErrorDetails()
                                 {
                                     ChargeBoxId = session.ChargeBoxId,
@@ -320,7 +342,7 @@ namespace EVCB_OCPP.WSServer.Message
                             {
 
 
-                                using (var db = new MeterValueDBContext())
+                                using (var db = await metervaluedbContextFactory.CreateDbContextAsync())
                                 {
                                     foreach (var item in _request.meterValue)
                                     {
@@ -335,7 +357,7 @@ namespace EVCB_OCPP.WSServer.Message
                                                 energyRegister = energy_Register.unit.Value == UnitOfMeasure.kWh ? decimal.Multiply(energyRegister, 1000) : energyRegister;
 
 
-                                                using (var maindb = new MainDBContext())
+                                                using (var maindb = await maindbContextFactory.CreateDbContextAsync())
                                                 {
                                                     meterStart = maindb.TransactionRecord.Where(x => x.Id == _request.transactionId.Value).Select(x => x.MeterStart).FirstOrDefault();
                                                 }
@@ -377,12 +399,7 @@ namespace EVCB_OCPP.WSServer.Message
                                               new SqlParameter("TransactionId",_request.transactionId.HasValue?_request.transactionId:-1),
                                           };
 
-
-                                            db.Database.ExecuteSqlCommand(sp, parameter.ToArray());
-
-
-
-
+                                            db.Database.ExecuteSqlRaw(sp, parameter.ToArray());
                                         }
 
                                     }
@@ -396,7 +413,7 @@ namespace EVCB_OCPP.WSServer.Message
                                     if (session.IsBilling)
                                         if (session.IsBilling)
                                         {
-                                            using (var db = new MainDBContext())
+                                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                                             {
                                                 db.ServerMessage.Add(new ServerMessage()
                                                 {
@@ -444,7 +461,7 @@ namespace EVCB_OCPP.WSServer.Message
 
                             int _transactionId = -1;
 
-                            var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+                            var businessService = await serviceProvider.GetService<BusinessServiceFactory>().CreateBusinessService(session.CustomerId.ToString());
 
                             var _idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted };
                             if (_request.idTag != "Backend")
@@ -494,7 +511,7 @@ namespace EVCB_OCPP.WSServer.Message
                             }
 
 
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var _CustomerId = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).Include(x => x.Customer).
                                      Select(x => x.CustomerId).FirstOrDefault();
@@ -534,14 +551,14 @@ namespace EVCB_OCPP.WSServer.Message
                                     db.SaveChanges();
 
                                     _transactionId = _newTransaction.Id;
-                                    logger.Info("***************************************************** ");
-                                    logger.Info(string.Format("{0} :TransactionId {1} ", session.ChargeBoxId, _newTransaction.Id));
-                                    logger.Info("***************************************************** ");
+                                    logger.LogInformation("***************************************************** ");
+                                    logger.LogInformation(string.Format("{0} :TransactionId {1} ", session.ChargeBoxId, _newTransaction.Id));
+                                    logger.LogInformation("***************************************************** ");
                                 }
                                 else
                                 {
                                     _transactionId = _existedTx.Id;
-                                    logger.Error("Duplication ***************************************************** " + _existedTx.Id);
+                                    logger.LogError("Duplication ***************************************************** " + _existedTx.Id);
                                 }
                             }
 
@@ -563,7 +580,7 @@ namespace EVCB_OCPP.WSServer.Message
 
                             int _ConnectorId = 0;
 
-                            var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+                            var businessService = await serviceProvider.GetService<BusinessServiceFactory>().CreateBusinessService(session.CustomerId.ToString());
 
                             var _idTagInfo = string.IsNullOrEmpty(_request.idTag) ? null : (_request.idTag == "Backend" ?
                                 new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted } : (await businessService.Authorize(session.ChargeBoxId, _request.idTag)).IdTagInfo);
@@ -575,7 +592,7 @@ namespace EVCB_OCPP.WSServer.Message
                             }
                             try
                             {                              
-                                using (var db = new MainDBContext())
+                                using (var db = await maindbContextFactory.CreateDbContextAsync())
                                 {
                                     var transaction = db.TransactionRecord.Where(x => x.Id == _request.transactionId
                                      && x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
@@ -684,7 +701,7 @@ namespace EVCB_OCPP.WSServer.Message
                                 {
                                     if (_request.transactionData.Count > 0)
                                     {
-                                        using (var _meterDb = new MeterValueDBContext())
+                                        using (var _meterDb = await metervaluedbContextFactory.CreateDbContextAsync())
                                         {
                                             foreach (var item in _request.transactionData)
                                             {
@@ -712,7 +729,7 @@ namespace EVCB_OCPP.WSServer.Message
                                           };
 
 
-                                                    _meterDb.Database.ExecuteSqlCommand(sp, parameter.ToArray());
+                                                    _meterDb.Database.ExecuteSqlRaw(sp, parameter.ToArray());
                                                 }
                                             }
                                         }
@@ -736,7 +753,7 @@ namespace EVCB_OCPP.WSServer.Message
                         {
                             AuthorizeRequest _request = request as AuthorizeRequest;
 
-                            var businessService = BusinessServiceFactory.CreateBusinessService(session.CustomerId.ToString());
+                            var businessService = await serviceProvider.GetService<BusinessServiceFactory>().CreateBusinessService(session.CustomerId.ToString());
                             var confirm = new AuthorizeConfirmation()
                             {
                                 idTagInfo = new IdTagInfo() { expiryDate = DateTime.UtcNow.AddDays(1), status = AuthorizationStatus.Accepted }
@@ -796,9 +813,9 @@ namespace EVCB_OCPP.WSServer.Message
             }
             catch (Exception ex)
             {
-                logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action));
-                logger.Fatal(string.Format("Data {0}", request.ToString()));
-                logger.Fatal(string.Format("Error {0}", ex.ToString()));
+                logger.LogCritical("chargeBoxId:{0} {1}", session?.ChargeBoxId, action);
+                logger.LogCritical("Data {0}", request?.ToString());
+                logger.LogCritical("Error {0}", ex.ToString());
                 result.Exception = ex;
             }
 
@@ -808,7 +825,7 @@ namespace EVCB_OCPP.WSServer.Message
                 watch.Stop();
                 if (watch.ElapsedMilliseconds / 1000 > 3)
                 {
-                    logger.Error("Processing Hearbeat costs " + watch.ElapsedMilliseconds / 1000 + " seconds");
+                    logger.LogError("Processing Hearbeat costs " + watch.ElapsedMilliseconds / 1000 + " seconds");
                 }
             }
             return result;
@@ -827,7 +844,7 @@ namespace EVCB_OCPP.WSServer.Message
                         {
                             DataTransferConfirmation _confirm = confirm as DataTransferConfirmation;
                             DataTransferRequest _request = _confirm.GetRequest() as DataTransferRequest;
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                                 x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -845,8 +862,8 @@ namespace EVCB_OCPP.WSServer.Message
                                     var machine = new Machine() { Id = session.MachineId };
                                     if (machine != null)
                                     {
-                                        db.Configuration.AutoDetectChangesEnabled = false;
-                                        db.Configuration.ValidateOnSaveEnabled = false;
+                                        //db.Configuration.AutoDetectChangesEnabled = false;
+                                        //db.Configuration.ValidateOnSaveEnabled = false;
                                         db.Machine.Attach(machine);
                                         machine.BoardVersions = _confirm.data;
                                         db.Entry(machine).Property(x => x.BoardVersions).IsModified = true;
@@ -1060,7 +1077,7 @@ namespace EVCB_OCPP.WSServer.Message
 
                                                 };
 
-                                                logger.Debug("completed_session " + JsonConvert.SerializeObject(request));
+                                                logger.LogDebug("completed_session " + JsonConvert.SerializeObject(request));
                                                 var response = await httpClient.Post(customerInfo.ApiUrl + "completed_session", new Dictionary<string, string>()
                                                 {
                                                     { "PartnerId",session.CustomerId.ToString()}
@@ -1068,7 +1085,7 @@ namespace EVCB_OCPP.WSServer.Message
                                                 }, request, customerInfo.ApiKey);
 
                                                 var _httpResult = JsonConvert.DeserializeObject<CPOOuterResponse>(response.Response);
-                                                logger.Debug("completed_session Response" + response.Response);
+                                                logger.LogDebug("completed_session Response" + response.Response);
                                                 JObject jo = JObject.Parse(_httpResult.Data);
                                                 if (jo.ContainsKey("CouponPoint"))
                                                 {
@@ -1084,8 +1101,8 @@ namespace EVCB_OCPP.WSServer.Message
 
                                             tx.Receipt = receipt;
                                             tx.BillingDone = true;
-                                            db.Configuration.AutoDetectChangesEnabled = false;
-                                            db.Configuration.ValidateOnSaveEnabled = false;
+                                            //db.Configuration.AutoDetectChangesEnabled = false;
+                                            //db.Configuration.ValidateOnSaveEnabled = false;
                                             db.TransactionRecord.Attach(tx);
                                             db.Entry(tx).Property(x => x.Cost).IsModified = true;
                                             db.Entry(tx).Property(x => x.Receipt).IsModified = true;
@@ -1127,7 +1144,7 @@ namespace EVCB_OCPP.WSServer.Message
 
                                             await db.SaveChangesAsync();
 
-                                            using (var meterdb = new MeterValueDBContext())
+                                            using (var meterdb = await metervaluedbContextFactory.CreateDbContextAsync())
                                             {
                                                 string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," +
                                    "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId";
@@ -1148,7 +1165,7 @@ namespace EVCB_OCPP.WSServer.Message
                                                 };
 
 
-                                                meterdb.Database.ExecuteSqlCommand(sp, parameter.ToArray());
+                                                meterdb.Database.ExecuteSqlRaw(sp, parameter.ToArray());
                                             }
 
                                             using (SqlConnection conn = new SqlConnection(webConnectionString))
@@ -1213,7 +1230,7 @@ namespace EVCB_OCPP.WSServer.Message
 
                                             await db.SaveChangesAsync();
 
-                                            using (var meterdb = new MeterValueDBContext())
+                                            using (var meterdb = await metervaluedbContextFactory.CreateDbContextAsync())
                                             {
                                                 string sp = "[dbo].[uspInsertMeterValueRecord] @ChargeBoxId," +
                        "@ConnectorId,@Value,@CreatedOn,@ContextId,@FormatId,@MeasurandId,@PhaseId,@LocationId,@UnitId,@TransactionId";
@@ -1234,7 +1251,7 @@ namespace EVCB_OCPP.WSServer.Message
                                                 };
 
 
-                                                meterdb.Database.ExecuteSqlCommand(sp, parameter.ToArray());
+                                                meterdb.Database.ExecuteSqlRaw(sp, parameter.ToArray());
                                             }
 
                                         }
@@ -1266,7 +1283,7 @@ namespace EVCB_OCPP.WSServer.Message
 
                                         }, request, GlobalConfig.TCC_SALTKEY);
 
-                                        logger.Debug(JsonConvert.SerializeObject(response));
+                                        logger.LogDebug(JsonConvert.SerializeObject(response));
                                     }
 
                                 }
@@ -1280,7 +1297,7 @@ namespace EVCB_OCPP.WSServer.Message
                             ChangeAvailabilityConfirmation _confirm = confirm as ChangeAvailabilityConfirmation;
                             ChangeAvailabilityRequest _request = _confirm.GetRequest() as ChangeAvailabilityRequest;
 
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                                 x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -1302,7 +1319,7 @@ namespace EVCB_OCPP.WSServer.Message
                             ClearCacheConfirmation _confirm = confirm as ClearCacheConfirmation;
                             ClearCacheRequest _request = _confirm.GetRequest() as ClearCacheRequest;
 
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                                 x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -1323,7 +1340,7 @@ namespace EVCB_OCPP.WSServer.Message
                             RemoteStartTransactionConfirmation _confirm = confirm as RemoteStartTransactionConfirmation;
                             RemoteStartTransactionRequest _request = _confirm.GetRequest() as RemoteStartTransactionRequest;
 
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                                 x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -1344,7 +1361,7 @@ namespace EVCB_OCPP.WSServer.Message
                             RemoteStopTransactionConfirmation _confirm = confirm as RemoteStopTransactionConfirmation;
                             RemoteStopTransactionRequest _request = _confirm.GetRequest() as RemoteStopTransactionRequest;
 
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                                 x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -1365,7 +1382,7 @@ namespace EVCB_OCPP.WSServer.Message
                             ResetConfirmation _confirm = confirm as ResetConfirmation;
                             ResetRequest _request = _confirm.GetRequest() as ResetRequest;
 
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                                 x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -1386,7 +1403,7 @@ namespace EVCB_OCPP.WSServer.Message
                             ChangeConfigurationConfirmation _confirm = confirm as ChangeConfigurationConfirmation;
                             ChangeConfigurationRequest _request = _confirm.GetRequest() as ChangeConfigurationRequest;
 
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                          x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -1402,7 +1419,7 @@ namespace EVCB_OCPP.WSServer.Message
 
                                 if (_confirm.status == Packet.Messages.SubTypes.ConfigurationStatus.Accepted || _confirm.status == Packet.Messages.SubTypes.ConfigurationStatus.RebootRequired)
                                 {
-                                    var configure = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList();
+                                    var configure = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList();
 
                                     var foundConfig = configure.Find(x => x.ConfigureName == _request.key);
                                     if (foundConfig != null)
@@ -1412,7 +1429,7 @@ namespace EVCB_OCPP.WSServer.Message
                                     }
                                     else
                                     {
-                                        db.MachineConfiguration.Add(new MachineConfiguration()
+                                        db.MachineConfigurations.Add(new MachineConfiguration()
                                         {
                                             ChargeBoxId = session.ChargeBoxId,
                                             ConfigureName = _request.key,
@@ -1434,9 +1451,9 @@ namespace EVCB_OCPP.WSServer.Message
                                 GetConfigurationConfirmation _confirm = confirm as GetConfigurationConfirmation;
                                 //  GetConfigurationRequest _request = _confirm.GetRequest() as GetConfigurationRequest;
 
-                                using (var db = new MainDBContext())
+                                using (var db = await maindbContextFactory.CreateDbContextAsync())
                                 {
-                                    var configure = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList();
+                                    var configure = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId).ToList();
 
                                     if (_confirm.configurationKey != null)
                                     {
@@ -1467,7 +1484,7 @@ namespace EVCB_OCPP.WSServer.Message
                                             }
                                             else
                                             {
-                                                db.MachineConfiguration.Add(new MachineConfiguration()
+                                                db.MachineConfigurations.Add(new MachineConfiguration()
                                                 {
                                                     ChargeBoxId = session.ChargeBoxId,
                                                     ConfigureName = item.key,
@@ -1494,7 +1511,7 @@ namespace EVCB_OCPP.WSServer.Message
                                             }
                                             else
                                             {
-                                                db.MachineConfiguration.Add(new MachineConfiguration()
+                                                db.MachineConfigurations.Add(new MachineConfiguration()
                                                 {
                                                     ChargeBoxId = session.ChargeBoxId,
                                                     ConfigureName = item
@@ -1521,7 +1538,7 @@ namespace EVCB_OCPP.WSServer.Message
                             }
                             catch (Exception ex)
                             {
-                                logger.Error(ex.ToString());
+                                logger.LogError(ex.ToString());
                             }
 
                         }
@@ -1531,7 +1548,7 @@ namespace EVCB_OCPP.WSServer.Message
                             UnlockConnectorConfirmation _confirm = confirm as UnlockConnectorConfirmation;
                             UnlockConnectorRequest _request = _confirm.GetRequest() as UnlockConnectorRequest;
 
-                            using (var db = new MainDBContext())
+                            using (var db = await maindbContextFactory.CreateDbContextAsync())
                             {
                                 var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                                 x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -1556,7 +1573,7 @@ namespace EVCB_OCPP.WSServer.Message
             }
             catch (Exception ex)
             {
-                logger.Debug("123 " + action + " " + ex.ToString());
+                logger.LogDebug("123 " + action + " " + ex.ToString());
             }
 
 
@@ -1583,10 +1600,10 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         if (action == Actions.DataTransfer)
                         {
-                            logger.Debug(string.Format("DataTransfer Error {0}: {1}", session.ChargeBoxId, requestId));
+                            logger.LogDebug(string.Format("DataTransfer Error {0}: {1}", session.ChargeBoxId, requestId));
                         }
 
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();

+ 8 - 7
EVCB_OCPP.WSServer/Message/FirmwareManagementProfileHandler.cs

@@ -8,6 +8,7 @@ using OCPPServer.Protocol;
 using System;
 using System.Data.Entity;
 using System.Linq;
+using Microsoft.Extensions.Logging;
 
 namespace EVCB_OCPP.WSServer.Message
 {
@@ -28,7 +29,7 @@ namespace EVCB_OCPP.WSServer.Message
                             if (_request.status == Packet.Messages.SubTypes.FirmwareStatus.Idle)
                             {
                                 string requestId = Guid.NewGuid().ToString();
-                                using (var db = new MainDBContext())
+                                using (var db = maindbContextFactory.CreateDbContext())
                                 {
                                     var machine = db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true && x.FW_AssignedVersion.HasValue
                                        && x.FW_AssignedVersion != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
@@ -83,7 +84,7 @@ namespace EVCB_OCPP.WSServer.Message
                             }
                             else
                             {
-                                using (var db = new MainDBContext())
+                                using (var db = maindbContextFactory.CreateDbContext())
                                 {
                                     var item = db.MachineOperateRecord.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.RequestType == 0)
                                         .OrderByDescending(x => x.CreatedOn).FirstOrDefault();
@@ -138,9 +139,9 @@ namespace EVCB_OCPP.WSServer.Message
             }
             catch (Exception ex)
             {
-                logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action));
-                logger.Fatal(string.Format("Data {0}", request.ToString()));
-                logger.Fatal(string.Format("Error {0}", ex.ToString()));
+                logger.LogCritical("chargeBoxId:{0} {1}", session.ChargeBoxId, action);
+                logger.LogCritical("Data {0}", request.ToString());
+                logger.LogCritical("Error {0}", ex.ToString());
                 result.Exception = ex;
             }
             return result;
@@ -161,7 +162,7 @@ namespace EVCB_OCPP.WSServer.Message
                             var confirmation = confirm as GetDiagnosticsConfirmation;
                             evse_rep = confirmation.fileName;
                         }
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -198,7 +199,7 @@ namespace EVCB_OCPP.WSServer.Message
                 case Actions.GetDiagnostics:
                 case Actions.DiagnosticsStatusNotification:
                     {
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();

+ 3 - 7
EVCB_OCPP.WSServer/Message/LocalAuthListManagementProfileHandler.cs

@@ -10,10 +10,6 @@ namespace EVCB_OCPP.WSServer.Message
 {
     internal partial class ProfileHandler
     {
-
-
-
-
         internal MessageResult ExecuteLocalAuthListManagementConfirm(Actions action, ClientData session, IConfirmation confirm, string requestId)
         {
             MessageResult result = new MessageResult() { Success = true };
@@ -24,7 +20,7 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         GetLocalListVersionConfirmation _confirm = confirm as GetLocalListVersionConfirmation;
                         GetLocalListVersionRequest _request = _confirm.GetRequest() as GetLocalListVersionRequest;
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -44,7 +40,7 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         SendLocalListConfirmation _confirm = confirm as SendLocalListConfirmation;
                         SendLocalListRequest _request = _confirm.GetRequest() as SendLocalListRequest;
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -79,7 +75,7 @@ namespace EVCB_OCPP.WSServer.Message
                 case Actions.SendLocalList:
                 case Actions.GetLocalListVersion:
                     {
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();

+ 5 - 4
EVCB_OCPP.WSServer/Message/OCPP16MessageHandler.cs

@@ -1,9 +1,10 @@
 using EVCB_OCPP.Packet.Features;
 using EVCB_OCPP.Packet.Messages;
 using EVCB_OCPP.Packet.Messages.Basic;
+using Microsoft.Extensions.Logging;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
-using NLog;
+
 using OCPPServer.Protocol;
 using System;
 using System.Collections.Generic;
@@ -17,7 +18,7 @@ namespace EVCB_OCPP.WSServer.Message
     /// </summary>
     internal class OCPP16MessageHandler
     {
-        static protected ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        static protected ILogger logger;
 
         #region 傳送 or 解析訊息需要欄位
         private const int INDEX_MESSAGEID = 0;
@@ -277,7 +278,7 @@ namespace EVCB_OCPP.WSServer.Message
             catch (Exception ex)
             {
                 result.Exception = ex;
-                logger.Error(string.Format("[{0}]UnPackPayloadbyCall Ex: {1}", action, ex.Message), "UnPack");
+                logger.LogError(string.Format("[{0}]UnPackPayloadbyCall Ex: {1}", action, ex.Message), "UnPack");
 
             }
 
@@ -325,7 +326,7 @@ namespace EVCB_OCPP.WSServer.Message
             catch (Exception ex)
             {
                 result.Exception = ex;
-                logger.Error(string.Format(i+"UnPackPayloadbyCallResult Data:[{0},{1}] Ex: {2}", uniqueId, payload, ex.ToString()), "UnPack");
+                logger.LogError(string.Format(i+"UnPackPayloadbyCallResult Data:[{0},{1}] Ex: {2}", uniqueId, payload, ex.ToString()), "UnPack");
 
             }
             return result;

+ 5 - 4
EVCB_OCPP.WSServer/Message/OCPP20MessageHandler.cs

@@ -1,9 +1,10 @@
 using EVCB_OCPP.Packet.Messages;
 using EVCB_OCPP.Packet.Messages.Basic;
 using EVCB_OCPP20.Packet.Features;
+using Microsoft.Extensions.Logging;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
-using NLog;
+
 using OCPPServer.Protocol;
 using System;
 using I20Confirmation = EVCB_OCPP20.Packet.Messages.IConfirmation;
@@ -18,7 +19,7 @@ namespace EVCB_OCPP.WSServer.Message
     /// </summary>
     internal class OCPP20MessageHandler
     {
-        static protected ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        static protected ILogger logger;
 
         #region 傳送 or 解析訊息需要欄位
         private const int INDEX_MESSAGEID = 0;
@@ -257,7 +258,7 @@ namespace EVCB_OCPP.WSServer.Message
             catch (Exception ex)
             {
                 result.Exception = ex;
-                logger.Error(string.Format("[{0}]UnPackPayloadbyCall Ex: {1}", action, ex.Message), "UnPack");
+                logger.LogError(string.Format("[{0}]UnPackPayloadbyCall Ex: {1}", action, ex.Message), "UnPack");
 
             }
 
@@ -280,7 +281,7 @@ namespace EVCB_OCPP.WSServer.Message
             catch (Exception ex)
             {
                 result.Exception = ex;
-                logger.Error(string.Format("UnPackPayloadbyCallResult Data:[{0},{1}] Ex: {2}", uniqueId, payload, ex.ToString()), "UnPack");
+                logger.LogError(string.Format("UnPackPayloadbyCallResult Data:[{0},{1}] Ex: {2}", uniqueId, payload, ex.ToString()), "UnPack");
 
             }
             return result;

+ 2 - 2
EVCB_OCPP.WSServer/Message/RemoteTriggerHandler.cs

@@ -22,7 +22,7 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         TriggerMessageConfirmation _confirm = confirm as TriggerMessageConfirmation;
                         TriggerMessageRequest _request = _confirm.GetRequest() as TriggerMessageRequest;
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -56,7 +56,7 @@ namespace EVCB_OCPP.WSServer.Message
             {
                 case Actions.TriggerMessage:
                     {
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();

+ 4 - 4
EVCB_OCPP.WSServer/Message/ReservationProfileHandler.cs

@@ -22,7 +22,7 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         ReserveNowConfirmation _confirm = confirm as ReserveNowConfirmation;
                         ReserveNowRequest _request = _confirm.GetRequest() as ReserveNowRequest;
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -42,7 +42,7 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         CancelReservationConfirmation _confirm = confirm as CancelReservationConfirmation;
                         CancelReservationRequest _request = _confirm.GetRequest() as CancelReservationRequest;
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -76,7 +76,7 @@ namespace EVCB_OCPP.WSServer.Message
             {
                 case Actions.ReserveNow:
                     {
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -94,7 +94,7 @@ namespace EVCB_OCPP.WSServer.Message
                     break;
                 case Actions.CancelReservation:
                     {
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();

+ 4 - 3
EVCB_OCPP.WSServer/Message/SecurityProfileHandler.cs

@@ -2,6 +2,7 @@
 using EVCB_OCPP.Packet.Messages;
 using OCPPServer.Protocol;
 using System;
+using Microsoft.Extensions.Logging;
 
 namespace EVCB_OCPP.WSServer.Message
 {
@@ -26,9 +27,9 @@ namespace EVCB_OCPP.WSServer.Message
             }
             catch (Exception ex)
             {
-                logger.Fatal(string.Format("chargeBoxId:{0} {1}", session.ChargeBoxId, action));
-                logger.Fatal(string.Format("Data {0}", request.ToString()));
-                logger.Fatal(string.Format("Error {0}", ex.ToString()));
+                logger.LogCritical("chargeBoxId:{0} {1}", session.ChargeBoxId, action);
+                logger.LogCritical("Data {0}", request.ToString());
+                logger.LogCritical("Error {0}", ex.ToString());
                 result.Exception = ex;
             }
 

+ 6 - 6
EVCB_OCPP.WSServer/Message/SmartChargingProfileHandler.cs

@@ -18,7 +18,7 @@ namespace EVCB_OCPP.WSServer.Message
 
         internal void SetChargingProfile(string chargeBoxId, decimal value, ChargingRateUnitType unit)
         {
-            using (var db = new MainDBContext())
+            using (var db = maindbContextFactory.CreateDbContext())
             {
                 var _setProfileRequest = new SetChargingProfileRequest()
                 {
@@ -62,7 +62,7 @@ namespace EVCB_OCPP.WSServer.Message
 
         internal void ClearChargingProfile(string chargeBoxId)
         {
-            using (var db = new MainDBContext())
+            using (var db = maindbContextFactory.CreateDbContext())
             {
                 var _clearProfileRequest = new ClearChargingProfileRequest()
                 {
@@ -102,7 +102,7 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         ClearChargingProfileConfirmation _confirm = confirm as ClearChargingProfileConfirmation;
                         ClearChargingProfileRequest _request = _confirm.GetRequest() as ClearChargingProfileRequest;
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -122,7 +122,7 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         SetChargingProfileConfirmation _confirm = confirm as SetChargingProfileConfirmation;
                         SetChargingProfileRequest _request = _confirm.GetRequest() as SetChargingProfileRequest;
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -142,7 +142,7 @@ namespace EVCB_OCPP.WSServer.Message
                     {
                         GetCompositeScheduleConfirmation _confirm = confirm as GetCompositeScheduleConfirmation;
                         GetCompositeScheduleRequest _request = _confirm.GetRequest() as GetCompositeScheduleRequest;
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();
@@ -178,7 +178,7 @@ namespace EVCB_OCPP.WSServer.Message
                 case Actions.SetChargingProfile:
                 case Actions.GetCompositeSchedule:
                     {
-                        using (var db = new MainDBContext())
+                        using (var db = maindbContextFactory.CreateDbContext())
                         {
                             var operation = db.MachineOperateRecord.Where(x => x.SerialNo == requestId &&
                             x.ChargeBoxId == session.ChargeBoxId && x.Status == 0).FirstOrDefault();

+ 52 - 7
EVCB_OCPP.WSServer/Program.cs

@@ -1,7 +1,17 @@
-using Newtonsoft.Json;
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.WSServer.Message;
+using EVCB_OCPP.WSServer.Service;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
 using System;
-using System.Net.Http;
-using System.Threading.Tasks;
+using NLog;
+using NLog.Web;
+using NLog.Extensions.Logging;
+using System.IO;
 
 namespace EVCB_OCPP.WSServer
 {
@@ -25,11 +35,46 @@ namespace EVCB_OCPP.WSServer
             Console.WriteLine("==                                                                                                ==");
             Console.WriteLine("====================================================================================================");
             Console.WriteLine("====================================================================================================");
-            ProtalServer s = new ProtalServer();
-            Console.WriteLine("Starting Server...");
-            s.Start();
 
-            Console.Read();
+
+            IHost host = Host.CreateDefaultBuilder(args)
+                .ConfigureLogging((context, builder) => { 
+                    builder.ClearProviders();
+                    NLog.LogManager.Configuration = new NLogLoggingConfiguration(context.Configuration.GetSection("NLog"));
+                })
+                .UseNLog()
+                .ConfigureServices((hostContext, services) =>
+                {
+                    services.AddDbContextFactory<MainDBContext>((options) => {
+                        var cString = hostContext.Configuration.GetConnectionString("MainDBContext");
+                        options.UseSqlServer(cString);
+                    });
+                    services.AddDbContextFactory<MeterValueDBContext>((options) => {
+                        var cString = hostContext.Configuration.GetConnectionString("MeterValueDBContext");
+                        options.UseSqlServer(cString);
+                    });
+                    services.AddDbContextFactory<ConnectionLogDBContext>((options) => {
+                        var cString = hostContext.Configuration.GetConnectionString("ConnectionLogDBContext");
+                        options.UseSqlServer(cString);
+                    });
+
+                    services.AddScoped<ProfileHandler>();
+
+                    services.AddScoped<LocalBusinessService>();
+                    services.AddScoped<CPOOuterResponse>();
+                    services.AddSingleton<BusinessServiceFactory>();
+
+                    services.AddHostedService<ProtalServer>();
+                })
+                .Build();
+
+            host.Run();
+
+            //ProtalServer s = new ProtalServer();
+            //Console.WriteLine("Starting Server...");
+            //s.Start();
+
+            //Console.Read();
         }
 
         public static object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)

+ 4 - 4
EVCB_OCPP.WSServer/Properties/AssemblyInfo.cs

@@ -31,8 +31,8 @@ using System.Runtime.InteropServices;
 //
 // 您可以指定所有的值,或將組建編號或修訂編號設為預設值
 // 指定為預設值: 
-// [assembly: AssemblyVersion("1.2.0.0")]
-[assembly: AssemblyVersion("1.2.0.0")]
-[assembly: AssemblyFileVersion("1.2.0.0")]
+// [assembly: AssemblyVersion("1.2.1.0")]
+[assembly: AssemblyVersion("1.2.1.0")]
+[assembly: AssemblyFileVersion("1.2.1.0")]
 
-[assembly: AssemblyInformationalVersion("92c630c")]
+[assembly: AssemblyInformationalVersion("0bc54e3")]

+ 10 - 0
EVCB_OCPP.WSServer/Properties/launchSettings.json

@@ -0,0 +1,10 @@
+{
+  "profiles": {
+    "EVCB_OCPP.WSServer": {
+      "commandName": "Project"
+    },
+    "Docker": {
+      "commandName": "Docker"
+    }
+  }
+}

+ 247 - 57
EVCB_OCPP.WSServer/ProtalServer.cs

@@ -10,9 +10,10 @@ using EVCB_OCPP.WSServer.Dto;
 using EVCB_OCPP.WSServer.Helper;
 using EVCB_OCPP.WSServer.Message;
 using EVCB_OCPP.WSServer.Service;
+using Microsoft.Extensions.Hosting;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
-using NLog;
+
 using OCPPServer.Protocol;
 using OCPPServer.SubProtocol;
 using SuperSocket.SocketBase;
@@ -21,15 +22,21 @@ using System;
 using System.Collections.Generic;
 using System.Configuration;
 using System.Data;
-using System.Data.Entity;
-using System.Data.SqlClient;
 using System.Diagnostics;
 using System.Linq;
 using System.Security.Authentication;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Xml.Linq;
-
+using NLog;
+using Microsoft.Extensions.Configuration;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using ProtoBuf.Serializers;
+using System.Net;
+using Microsoft.AspNetCore.Builder;
+using NLog.Extensions.Logging;
+using Microsoft.Data.SqlClient;
 
 namespace EVCB_OCPP.WSServer
 {
@@ -47,7 +54,7 @@ namespace EVCB_OCPP.WSServer
             return true;
         }
     }
-    internal class ProtalServer
+    internal class ProtalServer : IHostedService
     {
         static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
         private OuterHttpClient httpClient = new OuterHttpClient();
@@ -55,12 +62,17 @@ namespace EVCB_OCPP.WSServer
         private Dictionary<string, ClientData> clientDic = new Dictionary<string, ClientData>();
         private readonly Object _lockClientDic = new object();
         private readonly Object _lockConfirmPacketList = new object();
-        private ProfileHandler profileHandler = new ProfileHandler();
+        private readonly IConfiguration configuration;
+        private readonly IServiceProvider serviceProvider;
+        private readonly IDbContextFactory<MainDBContext> maindbContextFactory;
+        private readonly ProfileHandler profileHandler;//= new ProfileHandler();
+        private readonly string webConnectionString;// = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+        private readonly bool isInDocker;
         private List<NeedConfirmMessage> needConfirmPacketList = new List<NeedConfirmMessage>();
         private DateTime checkUpdateDt = DateTime.UtcNow;
         private DateTime _CheckFeeDt = DateTime.UtcNow;
         private DateTime _CheckWeatherDt = DateTime.UtcNow;
-        private LoadingBalanceService _loadingBalanceService = new LoadingBalanceService();
+        private readonly LoadingBalanceService _loadingBalanceService;// = new LoadingBalanceService();
         private Dictionary<string, TCCWeatherDto> TCCStationDic = new Dictionary<string, TCCWeatherDto>();
 
         private List<string> needConfirmActions = new List<string>()
@@ -100,21 +112,41 @@ namespace EVCB_OCPP.WSServer
         private CancellationToken _ct;
         private string _ocpp20NetworkSetting = "";
 
-        internal ProtalServer()
+        public ProtalServer(
+            IConfiguration configuration
+            , IServiceProvider serviceProvider
+            , IDbContextFactory<MainDBContext> maindbContextFactory)
         {
             _ct = _cts.Token;
-            WarmUpLog();
 
+            this.configuration = configuration;
+            this.serviceProvider = serviceProvider;
+            this.maindbContextFactory = maindbContextFactory;
+            isInDocker = !string.IsNullOrEmpty(configuration["DOTNET_RUNNING_IN_CONTAINER"]);
 
+            webConnectionString = configuration.GetConnectionString("WebDBContext");
+            profileHandler = serviceProvider.GetService<ProfileHandler>();// new ProfileHandler(configuration, serviceProvider);
+            _loadingBalanceService = new LoadingBalanceService(configuration);
 
+            WarmUpLog();
+        }
 
+        public Task StartAsync(CancellationToken cancellationToken)
+        {
+            Start();
+            return Task.CompletedTask;
         }
 
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            return Task.CompletedTask;
+        }
 
         internal void Start()
         {
+            Console.WriteLine("Starting Server...");
 
-            if (!GlobalConfig.LoadAPPConfig())
+            if (!GlobalConfig.LoadAPPConfig(configuration))
             {
                 Console.WriteLine("Please check App.Config setting .");
                 return;
@@ -140,8 +172,23 @@ namespace EVCB_OCPP.WSServer
             Task serverHealthTask = new Task(HealthCheckTrigger, _ct);
             serverHealthTask.Start();
 
+            if (!isInDocker)
+            {
+                RunConsoleInteractive();
+                return;
+            }
+            RunHttpConsoleService();
+        }
+
+        private void RunConsoleInteractive()
+        {
             while (true)
             {
+                if (Console.In is null)
+                {
+                    break;
+                }
+
                 var input = Console.ReadLine();
 
                 switch (input.ToLower())
@@ -218,29 +265,57 @@ namespace EVCB_OCPP.WSServer
 
                     case "silent":
                         Console.WriteLine("Command silent");
-                        var xe = XElement.Load("NLog.config");
-                        var xns = xe.GetDefaultNamespace();
-                        var minlevelattr = xe.Descendants(xns + "rules").Elements(xns + "logger")
-                            .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
-                        if (minlevelattr != null)
+                        //var xe = XElement.Load("NLog.config");
+                        //var xns = xe.GetDefaultNamespace();
+                        //var minlevelattr = xe.Descendants(xns + "rules").Elements(xns + "logger")
+                        //    .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
+                        //if (minlevelattr != null)
+                        //{
+
+                        //    minlevelattr.Value = "Warn";
+                        //}
+                        //xe.Save("NLog.config");
+                        foreach (var rule in LogManager.Configuration.LoggingRules)
                         {
+                            if (rule.RuleName != "ConsoleLog")
+                            {
+                                continue;
+                            }
+
+                            var isTargetRule = rule.Targets.Any(x => x.Name.ToLower() == "console");
 
-                            minlevelattr.Value = "Warn";
+                            if (isTargetRule)
+                            {
+                                rule.SetLoggingLevels(LogLevel.Warn, LogLevel.Off);
+                            }
                         }
-                        xe.Save("NLog.config");
                         break;
                     case "show":
                         Console.WriteLine("Command show");
-                        var xe1 = XElement.Load("NLog.config");
-                        var xns1 = xe1.GetDefaultNamespace();
-                        var minlevelattr1 = xe1.Descendants(xns1 + "rules").Elements(xns1 + "logger")
-                            .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
-                        if (minlevelattr1 != null)
+                        //var xe1 = XElement.Load("NLog.config");
+                        //var xns1 = xe1.GetDefaultNamespace();
+                        //var minlevelattr1 = xe1.Descendants(xns1 + "rules").Elements(xns1 + "logger")
+                        //    .Where(c => c.Attribute("writeTo").Value.Equals("console")).Attributes("minlevel").FirstOrDefault();
+                        //if (minlevelattr1 != null)
+                        //{
+
+                        //    minlevelattr1.Value = "trace";
+                        //}
+                        //xe1.Save("NLog.config");
+                        foreach (var rule in LogManager.Configuration.LoggingRules)
                         {
+                            if (rule.RuleName != "ConsoleLog")
+                            {
+                                continue;
+                            }
 
-                            minlevelattr1.Value = "trace";
+                            var isTargetRule = rule.Targets.Any(x => x.Name.ToLower() == "console");
+
+                            if (isTargetRule)
+                            {
+                                rule.SetLoggingLevels(LogLevel.Trace, LogLevel.Off);
+                            }
                         }
-                        xe1.Save("NLog.config");
                         break;
                     case "rcl":
                         break;
@@ -250,6 +325,117 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
+        private void RunHttpConsoleService()
+        {
+            var app = WebApplication.Create();
+
+            var helpFunc = () => {
+                return string.Join("\r\n", new[] { 
+                    "Command help!!",
+                    "lcn : List Customer Name",
+                    "gc : GC Collect",
+                    "lc : List Clients",
+                    "silent : silent",
+                    "show : show log"
+                });
+            };
+            app.MapGet("/", helpFunc);
+            app.MapGet("/help", helpFunc);
+
+            app.MapPost("/stop", () => {
+                Stop();
+                return "Command stop";
+            });
+
+            app.MapPost("/gc", () => {
+                GC.Collect();
+                return "Command GC";
+            });
+
+            app.MapPost("/lc", () => {
+                List<string> toReturn = new List<string>() { "Command List Clients" };
+                Dictionary<string, ClientData> _copyClientDic = null;
+                lock (_lockClientDic)
+                {
+                    _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                }
+                var list = _copyClientDic.Select(c => c.Value).ToList();
+                var locations = _copyClientDic.Where(x => !string.IsNullOrEmpty(x.Value.StationLocation)).Distinct().Select(x => x.Value.StationLocation).ToList();
+                int i = 1;
+                foreach (var c in list)
+                {
+                    toReturn.Add(i + ":" + c.ChargeBoxId + " " + c.SessionID);
+                    i++;
+                }
+
+                foreach (var c in TCCStationDic)
+                {
+                    toReturn.Add(i + ":" + c.Key + "-" + c.Value.Temperature + "/" + c.Value.WeatherID);
+                    i++;
+                }
+                return string.Join("\r\n", toReturn);
+            });
+
+            app.MapPost("/lcn", () => {
+                List<string> toReturn = new List<string> { "Command List Customer Name" };
+                Dictionary<string, ClientData> _copyClientDic = null;
+                lock (_lockClientDic)
+                {
+                    _copyClientDic = new Dictionary<string, ClientData>(clientDic);
+
+                }
+                var lcn = clientDic.Select(c => c.Value.CustomerName).Distinct().ToList();
+                int iLcn = 1;
+                foreach (var c in lcn)
+                {
+                    toReturn.Add(iLcn + ":" + c + ":" + clientDic.Where(z => z.Value.CustomerName == c).Count().ToString());
+                    iLcn++;
+                }
+                return string.Join("\r\n", toReturn);
+            });
+
+            app.MapPost("/silent", () => {
+                foreach (var rule in LogManager.Configuration.LoggingRules)
+                {
+                    if (rule.RuleName != "ConsoleLog")
+                    {
+                        continue;
+                    }
+
+                    var isTargetRule = rule.Targets.Any(x => x.Name.ToLower() == "console");
+
+                    if (isTargetRule)
+                    {
+                        rule.SetLoggingLevels(LogLevel.Warn, LogLevel.Off);
+                    }
+                }
+                return "Command silent";
+            });
+
+            app.MapPost("/show", () => {
+                foreach (var rule in LogManager.Configuration.LoggingRules)
+                {
+                    if (rule.RuleName != "ConsoleLog")
+                    {
+                        continue;
+                    }
+
+                    var isTargetRule = rule.Targets.Any(x => x.Name.ToLower() == "console");
+
+                    if (isTargetRule)
+                    {
+                        rule.SetLoggingLevels(LogLevel.Trace, LogLevel.Off);
+                    }
+                }
+                return "Command show";
+            });
+
+            app.Urls.Add("http://*:54088");
+
+            _ = app.RunAsync();
+        }
+
         internal void Stop()
         {
             if (_cts != null)
@@ -261,7 +447,7 @@ namespace EVCB_OCPP.WSServer
         private void CheckVersion(string chargeBoxId)
         {
             if (string.IsNullOrEmpty(chargeBoxId)) return;
-            using (var db = new MainDBContext())
+            using (var db = maindbContextFactory.CreateDbContext())
             {
                 db.ServerMessage.Add(new ServerMessage()
                 {
@@ -291,7 +477,7 @@ namespace EVCB_OCPP.WSServer
         private void CheckEVSEConfigure(string chargeBoxId)
         {
             if (string.IsNullOrEmpty(chargeBoxId)) return;
-            using (var db = new MainDBContext())
+            using (var db = maindbContextFactory.CreateDbContext())
             {
                 db.ServerMessage.Add(new ServerMessage()
                 {
@@ -322,7 +508,7 @@ namespace EVCB_OCPP.WSServer
 
         private void ReadTCCSetting()
         {
-            using (var db = new MainDBContext())
+            using (var db = maindbContextFactory.CreateDbContext())
             {
                 var info = db.Customer.Where(x => x.Id == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).Select(x => new { x.ApiUrl, x.ApiKey }).FirstOrDefault();
                 GlobalConfig.TCC_API_URL = info.ApiUrl;
@@ -353,15 +539,19 @@ namespace EVCB_OCPP.WSServer
         {
 
             //載入OCPP Protocol
-            var appServer = new OCPPWSServer(new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") });
+            var appServer = new OCPPWSServer(
+                new List<OCPPSubProtocol>() { new OCPPSubProtocol(), new OCPPSubProtocol(" ocpp1.6"), new OCPPSubProtocol("ocpp2.0") }
+                ,serviceProvider);
 
             List<IListenerConfig> llistener = new List<IListenerConfig>();
 
             llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWS_Port()), Backlog = 100, Security = "None" });
             llistener.Add(new ListenerConfig { Ip = System.Net.IPAddress.Any.ToString(), Port = Convert.ToInt32(GlobalConfig.GetWSS_Port()), Backlog = 100, Security = SslProtocols.Tls12.ToString() });
 
-            var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource;
-            ICertificateConfig Certificate = config.Servers.ElementAt(0).Certificate;
+            //var config = ConfigurationManager.GetSection("superSocket") as IConfigurationSource;\
+            //var certificate = configuration.GetSection("superSocket").GetSection("Servers:0").GetSection("Certificate").Get<CertificateConfig>();
+            var certificate = configuration.GetSection("SuperSocketServerCertificate").Get<CertificateConfig>();
+            ICertificateConfig Certificate = certificate;
             IEnumerable<IListenerConfig> listeners = llistener;
 
             //設定server config
@@ -379,7 +569,7 @@ namespace EVCB_OCPP.WSServer
             };
 
             //Setup with listening port
-            if (!appServer.Setup(serverConfig, logFactory: new OCPPLogFactory()))
+            if (!appServer.Setup(serverConfig, logFactory: new NLogLoggerFactory()))
             {
                 Console.WriteLine("Failed to setup!");
                 return;
@@ -393,7 +583,7 @@ namespace EVCB_OCPP.WSServer
             if (!appServer.Start())
             {
                 Console.WriteLine("Failed to start!");
-                Console.ReadKey();
+                //Console.ReadKey();
                 return;
             }
         }
@@ -415,7 +605,7 @@ namespace EVCB_OCPP.WSServer
                     bool isNotSupported = session.SecWebSocketProtocol.Contains("ocpp1.6") ? false : session.SecWebSocketProtocol.Contains("ocpp2.0") ? false : true;
                     if (isNotSupported)
                     {
-                        //logger.Debug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol));
+                        //logger.LogDebug(string.Format("ChargeBoxId:{0} SecWebSocketProtocol:{1} NotSupported", session.ChargeBoxId, session.SecWebSocketProtocol));
                         WriteMachineLog(session, string.Format("SecWebSocketProtocol:{0} NotSupported", session.SecWebSocketProtocol), "Connection", "");
                         return;
                     }
@@ -432,10 +622,10 @@ namespace EVCB_OCPP.WSServer
 
                     clientDic.Add(session.ChargeBoxId, session);
                     session.m_ReceiveData += new ClientData.OCPPClientDataEventHandler<ClientData, String>(ReceivedMessage);
-                    // logger.Debug("------------New " + (session == null ? "Oops" : session.ChargeBoxId));
+                    // logger.LogDebug("------------New " + (session == null ? "Oops" : session.ChargeBoxId));
                     WriteMachineLog(session, "NewSessionConnected", "Connection", "");
 
-                    using (var db = new MainDBContext())
+                    using (var db = maindbContextFactory.CreateDbContext())
                     {
                         var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
                         if (machine != null)
@@ -725,7 +915,7 @@ namespace EVCB_OCPP.WSServer
                                         CheckEVSEConfigure(session.ChargeBoxId);
                                         if (session.CustomerId == new Guid("298918C0-6BB5-421A-88CC-4922F918E85E") || session.CustomerId == new Guid("9E6BFDCC-09FB-4DAB-A428-43FE507600A3"))
                                         {
-                                            using (var db = new MainDBContext())
+                                            using (var db = maindbContextFactory.CreateDbContext())
                                             {
                                                 db.ServerMessage.Add(new ServerMessage()
                                                 {
@@ -762,7 +952,7 @@ namespace EVCB_OCPP.WSServer
                                                 session.StationLocation = string.Format("{0},{1}", stationInfo.Lat, stationInfo.Long);
                                                 session.StationName = stationInfo.ZipCode;
                                             }
-                                            using (var db = new MainDBContext())
+                                            using (var db = maindbContextFactory.CreateDbContext())
                                             {
                                                 db.ServerMessage.Add(new ServerMessage()
                                                 {
@@ -847,7 +1037,7 @@ namespace EVCB_OCPP.WSServer
                                     }
                                     else
                                     {
-                                        using (var db = new MainDBContext())
+                                        using (var db = maindbContextFactory.CreateDbContext())
                                         {
                                             var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefault();
                                             if (machine != null)
@@ -871,7 +1061,7 @@ namespace EVCB_OCPP.WSServer
 
                                     StartTransactionConfirmation confirm = (StartTransactionConfirmation)replyResult.Message;
                                     StartTransactionRequest request = (StartTransactionRequest)analysisResult.Message;
-                                    using (var db = new MainDBContext())
+                                    using (var db = maindbContextFactory.CreateDbContext())
                                     {
                                         db.ServerMessage.Add(new ServerMessage()
                                         {
@@ -902,7 +1092,7 @@ namespace EVCB_OCPP.WSServer
                                     var authorizeRequest = (IRequest)analysisResult.Message as AuthorizeRequest;
                                     if (session.UserDisplayPrices.ContainsKey(authorizeRequest.idTag))
                                     {
-                                        using (var db = new MainDBContext())
+                                        using (var db = maindbContextFactory.CreateDbContext())
                                         {
                                             db.ServerMessage.Add(new ServerMessage()
                                             {
@@ -1239,7 +1429,7 @@ namespace EVCB_OCPP.WSServer
 
                     }
                     checkUpdateDt = DateTime.UtcNow;
-                    using (var db = new MainDBContext())
+                    using (var db = maindbContextFactory.CreateDbContext())
                     {
                         //var needUpdateChargers = db.Machine.Where(x => x.FW_AssignedMachineVersionId.HasValue == true &&
                         //    x.FW_AssignedMachineVersionId != x.FW_VersionReport && x.Online == true)
@@ -1260,7 +1450,7 @@ namespace EVCB_OCPP.WSServer
                                 {
 
                                     string requestId = Guid.NewGuid().ToString();
-                                    // using (var db = new MainDBContext())
+                                    // using (var db = maindbContextFactory.CreateDbContext())
 
                                     if (session.IsCheckIn && !session.ISOCPP20)
                                     {
@@ -1347,7 +1537,7 @@ namespace EVCB_OCPP.WSServer
                 }
             }
         }
-        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+        //string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
 
         async private void ServerMessageTrigger()
         {
@@ -1363,7 +1553,7 @@ namespace EVCB_OCPP.WSServer
                     RemoveConfirmMessage();
 
                     BasicMessageHandler msgAnalyser = new BasicMessageHandler();
-                    using (var db = new MainDBContext())
+                    using (var db = maindbContextFactory.CreateDbContext())
                     {
                         DateTime startDt = DateTime.UtcNow.AddSeconds(-30);
                         DateTime dt = new DateTime(1991, 1, 1);
@@ -1399,7 +1589,7 @@ namespace EVCB_OCPP.WSServer
                             string uuid = string.Empty;
                             if (clientDic.TryGetValue(charger_SN, out session))
                             {
-                                //logger.Debug(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss")));
+                                //logger.LogDebug(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss")));
 
                                 if (session.IsCheckIn && !session.ISOCPP20)
                                 {
@@ -1458,8 +1648,8 @@ namespace EVCB_OCPP.WSServer
 
                                         #region 更新資料表單一欄位
                                         var _UpdatedItem = new ServerMessage() { Id = item.Id, UpdatedOn = DateTime.UtcNow };
-                                        db.Configuration.AutoDetectChangesEnabled = false;//自動呼叫DetectChanges()比對所有的entry集合的每一個屬性Properties的新舊值
-                                        db.Configuration.ValidateOnSaveEnabled = false;// 因為Entity有些欄位必填,若不避開會有Validate錯誤
+                                        //db.Configuration.AutoDetectChangesEnabled = false;//自動呼叫DetectChanges()比對所有的entry集合的每一個屬性Properties的新舊值
+                                        //db.Configuration.ValidateOnSaveEnabled = false;// 因為Entity有些欄位必填,若不避開會有Validate錯誤
                                                                                        // var _UpdatedItem = db.ServerMessage.Where(x => x.Id == item.Id).FirstOrDefault();
                                         db.ServerMessage.Attach(_UpdatedItem);
                                         _UpdatedItem.UpdatedOn = DateTime.UtcNow;
@@ -1517,13 +1707,13 @@ namespace EVCB_OCPP.WSServer
                         watch.Start();
                         foreach (var session in clients)
                         {
-                            using (var db = new MainDBContext())
+                            using (var db = maindbContextFactory.CreateDbContext())
                             {
                                 var machine = new Machine() { Id = session.MachineId };
                                 if (machine != null)
                                 {
-                                    db.Configuration.AutoDetectChangesEnabled = false;
-                                    db.Configuration.ValidateOnSaveEnabled = false;
+                                    //db.Configuration.AutoDetectChangesEnabled = false;
+                                    //db.Configuration.ValidateOnSaveEnabled = false;
                                     db.Machine.Attach(machine);
                                     machine.HeartbeatUpdatedOn = DateTime.UtcNow;
                                     machine.ConnectionType = session.UriScheme.Equals("wss") ? 2 : 1;
@@ -1695,7 +1885,7 @@ namespace EVCB_OCPP.WSServer
                     var clients = _copyClientDic.Where(x => x.Value.CustomerId == new Guid("009E603C-79CD-4620-A2B8-D9349C0E8AD8")).
                     Select(x => new { ChargeBoxId = x.Value.ChargeBoxId, StationLocation = x.Value.StationLocation }).ToList();
 
-                    using (var db = new MainDBContext())
+                    using (var db = maindbContextFactory.CreateDbContext())
                     {
 
                         foreach (var client in clients)
@@ -1785,7 +1975,7 @@ namespace EVCB_OCPP.WSServer
                                 {
                                     clientDic[item.Key].DisplayPrice = displayPriceText;
 
-                                    using (var db = new MainDBContext())
+                                    using (var db = maindbContextFactory.CreateDbContext())
                                     {
                                         db.ServerMessage.Add(new ServerMessage()
                                         {
@@ -2024,7 +2214,7 @@ namespace EVCB_OCPP.WSServer
                     foundRequest.SentInterval = 0;
                     analysisResult.RequestId = foundRequest.RequestId;
 
-                    using (var db = new MainDBContext())
+                    using (var db = maindbContextFactory.CreateDbContext())
                     {
                         var sc = db.ServerMessage.Where(x => x.Id == foundRequest.Id).FirstOrDefault();
                         sc.InMessage = JsonConvert.SerializeObject(analysisResult.Message, Formatting.None);
@@ -2077,7 +2267,7 @@ namespace EVCB_OCPP.WSServer
                 }
                 catch (Exception ex)
                 {
-                    //logger.Warn("Close client socket error!!");
+                    //logger.LogWarning("Close client socket error!!");
                     logger.Warn(string.Format("Close client socket error!! {0} Msg:{1}", session.ChargeBoxId, ex.Message));
                 }
 
@@ -2116,7 +2306,7 @@ namespace EVCB_OCPP.WSServer
         {
             try
             {
-                using (var log = new ConnectionLogDBContext())
+                using (var log = serviceProvider.GetService<IDbContextFactory<ConnectionLogDBContext>>().CreateDbContext())
                 {
                     log.MachineConnectionLog.ToList();
                 }
@@ -2140,7 +2330,7 @@ namespace EVCB_OCPP.WSServer
                 {
                     logger.Fatal(clientData.Path + "]********************session ChargeBoxId null sessionId=" + clientData.SessionID);
                 }
-                using (var db = new ConnectionLogDBContext())
+                using (var db = serviceProvider.GetService<IDbContextFactory<ConnectionLogDBContext>>().CreateDbContext())
                 {
                     string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
                           "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session";
@@ -2157,7 +2347,7 @@ namespace EVCB_OCPP.WSServer
                       new  SqlParameter("Session",clientData.SessionID==null?"123":clientData.SessionID)
                };
 
-                    db.Database.ExecuteSqlCommand(sp, parameter);
+                    db.Database.ExecuteSqlRaw(sp, parameter);
                 }
             }
             catch (Exception ex)

+ 25 - 4
EVCB_OCPP.WSServer/Service/BusinessServiceFactory.cs

@@ -1,6 +1,8 @@
 using EVCB_OCPP.Domain;
 using EVCB_OCPP.Packet.Messages.SubTypes;
 using EVCB_OCPP.WSServer.Dto;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
 using System;
 using System.Linq;
 using System.Threading.Tasks;
@@ -18,18 +20,37 @@ namespace EVCB_OCPP.WSServer.Service
 
     }
 
-    static public class BusinessServiceFactory
+    public class BusinessServiceFactory
     {
+        public BusinessServiceFactory(IServiceProvider serviceProvider, IDbContextFactory<MainDBContext> mainDBContextFactory)
+        {
+            this.serviceProvider = serviceProvider;
+            this.mainDBContextFactory = mainDBContextFactory;
+        }
+
+        private readonly IServiceProvider serviceProvider;
+        private readonly IDbContextFactory<MainDBContext> mainDBContextFactory;
 
-        static public IBusinessService CreateBusinessService(string customerId)
+        public async Task<IBusinessService> CreateBusinessService(string customerId)
         {
             bool isCallOut = false;
-            using (var db = new MainDBContext())
+            using (var db = await mainDBContextFactory.CreateDbContextAsync())
             {
                 isCallOut = db.Customer.Where(x => x.Id == new Guid(customerId)).Select(x => x.CallPartnerApiOnSchedule).SingleOrDefault();
             }
 
-            return isCallOut ? new OuterBusinessService(customerId) : (IBusinessService)new LocalBusinessService(customerId);
+            //return isCallOut ? new OuterBusinessService(customerId) : new LocalBusinessService(customerId);
+            if(isCallOut)
+            {
+                OuterBusinessService outerBusinessService = serviceProvider.GetService<OuterBusinessService>();
+                outerBusinessService.CustomerId = customerId;
+                return outerBusinessService;
+            }
+            LocalBusinessService toReturn = serviceProvider.GetService<LocalBusinessService>();
+            toReturn.CustomerId = customerId;
+            return toReturn;
+
+            //return isCallOut ? new OuterBusinessService(customerId) : 
         }
 
     }

+ 7 - 5
EVCB_OCPP.WSServer/Service/LoadingBalanceService.cs

@@ -1,10 +1,11 @@
 using Dapper;
+using Microsoft.Data.SqlClient;
+using Microsoft.Extensions.Configuration;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Configuration;
 using System.Data;
-using System.Data.SqlClient;
 using System.Linq;
 
 namespace EVCB_OCPP.WSServer.Service
@@ -21,15 +22,16 @@ namespace EVCB_OCPP.WSServer.Service
 
     public class LoadingBalanceService
     {
-        string mainConnectionString = ConfigurationManager.ConnectionStrings["MainDBContext"].ConnectionString;
-        string webConnectionString = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
+        private readonly string mainConnectionString;
+        private readonly string webConnectionString;
 
         ConcurrentDictionary<int, object> _lockDic = new ConcurrentDictionary<int, object>();
 
 
-        public LoadingBalanceService()
+        public LoadingBalanceService(IConfiguration configuration)
         {
-
+            mainConnectionString = configuration.GetConnectionString("MainDBContext");
+            webConnectionString = configuration.GetConnectionString("WebDBContext");
         }
 
         public int GetStationIdByMachineId(string machineId)

+ 7 - 6
EVCB_OCPP.WSServer/Service/LocalBusinessService.cs

@@ -1,5 +1,6 @@
 using EVCB_OCPP.Packet.Messages.SubTypes;
 using EVCB_OCPP.WSServer.Dto;
+using Microsoft.Extensions.Configuration;
 using Newtonsoft.Json.Linq;
 using System;
 using System.Collections.Generic;
@@ -11,12 +12,12 @@ namespace EVCB_OCPP.WSServer.Service
 {
     public class LocalBusinessService : IBusinessService
     {
+        public string CustomerId { get; set; }
+        private readonly IConfiguration configuration;
 
-        string customerId = string.Empty;
-
-        public LocalBusinessService(string customerId)
+        public LocalBusinessService(IConfiguration configuration)
         {
-            this.customerId = customerId;
+            this.configuration = configuration;
         }
 
         async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag)
@@ -26,7 +27,7 @@ namespace EVCB_OCPP.WSServer.Service
 
             try
             {
-                if (customerId.ToUpper() == "009E603C-79CD-4620-A2B8-D9349C0E8AD8")
+                if (CustomerId.ToUpper() == "009E603C-79CD-4620-A2B8-D9349C0E8AD8")
                 {
                     info.IdTagInfo = new IdTagInfo() { status = AuthorizationStatus.Accepted };
                     return info;
@@ -36,7 +37,7 @@ namespace EVCB_OCPP.WSServer.Service
                 OuterHttpClient _client = new OuterHttpClient();
 
 
-                string url = ConfigurationManager.AppSettings["LocalAuthAPI"];
+                string url = configuration["LocalAuthAPI"];
 
 
                 HttpClientService service = new HttpClientService();

+ 20 - 14
EVCB_OCPP.WSServer/Service/OuterBusinessService.cs

@@ -1,6 +1,8 @@
 using EVCB_OCPP.Domain;
+using EVCB_OCPP.Domain.Models.Database;
 using EVCB_OCPP.Packet.Messages.SubTypes;
 using EVCB_OCPP.WSServer.Dto;
+using Microsoft.EntityFrameworkCore;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 using NLog;
@@ -49,11 +51,23 @@ namespace EVCB_OCPP.WSServer.Service
         static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
         private OuterHttpClient httpClient = new OuterHttpClient();
         private CustomerSignMaterial signMaterial = null;
-        private string CustomerId = string.Empty;
-        public OuterBusinessService(string customerId)
+
+        private string _CustomerId = string.Empty;
+        private readonly IDbContextFactory<MainDBContext> maindbContextFactory;
+
+        public string CustomerId
+        {
+            get => _CustomerId;
+            set
+            {
+                _CustomerId = value;
+                signMaterial = GetSign(_CustomerId);
+            }
+        }
+
+        public OuterBusinessService(IDbContextFactory<MainDBContext> maindbContextFactory)
         {
-            CustomerId = customerId;
-            signMaterial = GetSign(customerId);
+            this.maindbContextFactory = maindbContextFactory;
         }
 
 
@@ -166,21 +180,12 @@ namespace EVCB_OCPP.WSServer.Service
             {
                 if (signMaterial.CallsThirdParty)
                 {
-
-              
-
-
                     var response = await httpClient.Post(signMaterial.APIUrl + "connectorfault", new Dictionary<string, string>()
                             {
                                 { "PartnerId",signMaterial.Id}
 
                             }, details, signMaterial.SaltKey).ConfigureAwait(false);
-
-                  
-                   
                 }
-
-
             }
             catch (Exception ex)
             {
@@ -225,7 +230,8 @@ namespace EVCB_OCPP.WSServer.Service
             CustomerSignMaterial _customer = new CustomerSignMaterial();
 
 
-            using (var db = new MainDBContext())
+            //using (var db = new MainDBContext())
+            using (var db = maindbContextFactory.CreateDbContext())
             {
                 _customer = db.Customer.Where(x => x.Id == Id).Select(x => new CustomerSignMaterial() { Id = x.Id.ToString(), APIUrl = x.ApiUrl, SaltKey = x.ApiKey, CallsThirdParty = x.CallPartnerApiOnSchedule }).FirstOrDefault();
             }

+ 1 - 0
EVCB_OCPP.WSServer/SuperSocket.Command/ProcessCallCmd.cs

@@ -1,5 +1,6 @@
 using OCPPServer.Protocol;
 using SuperWebSocket.SubProtocol;
+using System.Threading.Tasks;
 
 namespace EVCB_OCPP.WSServer.SuperSocket.Command
 {

+ 1 - 0
EVCB_OCPP.WSServer/SuperSocket.Command/ProcessCallErrorCmd.cs

@@ -1,5 +1,6 @@
 using OCPPServer.Protocol;
 using SuperWebSocket.SubProtocol;
+using System.Threading.Tasks;
 
 namespace EVCB_OCPP.WSServer.SuperSocket.Command
 {

+ 1 - 0
EVCB_OCPP.WSServer/SuperSocket.Command/ProcessCallResultCmd.cs

@@ -1,5 +1,6 @@
 using OCPPServer.Protocol;
 using SuperWebSocket.SubProtocol;
+using System.Threading.Tasks;
 
 namespace EVCB_OCPP.WSServer.SuperSocket.Command
 {

+ 4 - 2
EVCB_OCPP.WSServer/SuperSocket.Protocol/ClientData.cs

@@ -1,10 +1,12 @@
 
 using EVCB_OCPP.Packet.Messages.Basic;
 using EVCB_OCPP.WSServer.Dto;
-using SuperSocket.SocketBase;
-using SuperWebSocket;
 using System;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using SuperWebSocket;
+using SuperSocket.SocketBase;
 
 namespace OCPPServer.Protocol
 {

+ 1 - 434
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPLog.cs

@@ -1,441 +1,8 @@
 
 
-using SuperSocket.SocketBase.Logging;
+using Microsoft.Extensions.Logging;
 using System;
 
 namespace OCPPServer.SubProtocol
 {
-    public class OCPPLog : ILog
-    {
-        private NLog.ILogger m_Log;
-
-        public OCPPLog(string name)
-        {
-            m_Log = NLog.LogManager.GetCurrentClassLogger();
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance is debug enabled.
-        /// </summary>
-        /// <value>
-        /// 	<c>true</c> if this instance is debug enabled; otherwise, <c>false</c>.
-        /// </value>
-        public bool IsDebugEnabled
-        {
-            get { return m_Log.IsDebugEnabled; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance is error enabled.
-        /// </summary>
-        /// <value>
-        /// 	<c>true</c> if this instance is error enabled; otherwise, <c>false</c>.
-        /// </value>
-        public bool IsErrorEnabled
-        {
-            get { return m_Log.IsErrorEnabled; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance is fatal enabled.
-        /// </summary>
-        /// <value>
-        /// 	<c>true</c> if this instance is fatal enabled; otherwise, <c>false</c>.
-        /// </value>
-        public bool IsFatalEnabled
-        {
-            get { return m_Log.IsFatalEnabled; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance is info enabled.
-        /// </summary>
-        /// <value>
-        /// 	<c>true</c> if this instance is info enabled; otherwise, <c>false</c>.
-        /// </value>
-        public bool IsInfoEnabled
-        {
-            get { return m_Log.IsInfoEnabled; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance is warn enabled.
-        /// </summary>
-        /// <value>
-        /// 	<c>true</c> if this instance is warn enabled; otherwise, <c>false</c>.
-        /// </value>
-        public bool IsWarnEnabled
-        {
-            get { return m_Log.IsWarnEnabled; }
-        }
-
-        /// <summary>
-        /// Logs the debug message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        public void Debug(object message)
-        {
-            m_Log.Debug(message);
-        }
-
-        /// <summary>
-        /// Logs the debug message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        /// <param name="exception">The exception.</param>
-        public void Debug(object message, Exception exception)
-        {
-            //m_Log.Debug((System.IFormatProvider)message, exception);
-            m_Log.Debug(exception, message.ToString());
-        }
-
-        /// <summary>
-        /// Logs the debug message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        public void DebugFormat(string format, object arg0)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the debug message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void DebugFormat(string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the debug message.
-        /// </summary>
-        /// <param name="provider">The provider.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void DebugFormat(IFormatProvider provider, string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the debug message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        public void DebugFormat(string format, object arg0, object arg1)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the debug message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        /// <param name="arg2">The arg2.</param>
-        public void DebugFormat(string format, object arg0, object arg1, object arg2)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the error message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        public void Error(object message)
-        {
-            m_Log.Error(message);
-        }
-
-        /// <summary>
-        /// Logs the error message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        /// <param name="exception">The exception.</param>
-        public void Error(object message, Exception exception)
-        {
-            //m_Log.Error((System.IFormatProvider)message, exception);
-            m_Log.Error(exception.ToString());
-        }
-
-        /// <summary>
-        /// Logs the error message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        public void ErrorFormat(string format, object arg0)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the error message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void ErrorFormat(string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the error message.
-        /// </summary>
-        /// <param name="provider">The provider.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void ErrorFormat(IFormatProvider provider, string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the error message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        public void ErrorFormat(string format, object arg0, object arg1)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the error message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        /// <param name="arg2">The arg2.</param>
-        public void ErrorFormat(string format, object arg0, object arg1, object arg2)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the fatal error message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        public void Fatal(object message)
-        {
-            m_Log.Fatal(message);
-        }
-
-        /// <summary>
-        /// Logs the fatal error message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        /// <param name="exception">The exception.</param>
-        public void Fatal(object message, Exception exception)
-        {
-            m_Log.Fatal((System.IFormatProvider)message, exception);
-        }
-
-        /// <summary>
-        /// Logs the fatal error message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        public void FatalFormat(string format, object arg0)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the fatal error message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void FatalFormat(string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the fatal error message.
-        /// </summary>
-        /// <param name="provider">The provider.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void FatalFormat(IFormatProvider provider, string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the fatal error message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        public void FatalFormat(string format, object arg0, object arg1)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the fatal error message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        /// <param name="arg2">The arg2.</param>
-        public void FatalFormat(string format, object arg0, object arg1, object arg2)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the info message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        public void Info(object message)
-        {
-            m_Log.Info(message);
-        }
-
-        /// <summary>
-        /// Logs the info message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        /// <param name="exception">The exception.</param>
-        public void Info(object message, Exception exception)
-        {
-            //m_Log.Info((System.IFormatProvider)message, exception);
-            m_Log.Info(exception, message.ToString());
-        }
-
-        /// <summary>
-        /// Logs the info message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        public void InfoFormat(string format, object arg0)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the info message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void InfoFormat(string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the info message.
-        /// </summary>
-        /// <param name="provider">The provider.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void InfoFormat(IFormatProvider provider, string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the info message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        public void InfoFormat(string format, object arg0, object arg1)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the info message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        /// <param name="arg2">The arg2.</param>
-        public void InfoFormat(string format, object arg0, object arg1, object arg2)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the warning message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        public void Warn(object message)
-        {
-            m_Log.Warn(message);
-        }
-
-        /// <summary>
-        /// Logs the warning message.
-        /// </summary>
-        /// <param name="message">The message.</param>
-        /// <param name="exception">The exception.</param>
-        public void Warn(object message, Exception exception)
-        {
-            //m_Log.Warn((System.IFormatProvider)message, exception);
-            m_Log.Warn(exception, message.ToString());
-        }
-
-        /// <summary>
-        /// Logs the warning message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        public void WarnFormat(string format, object arg0)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the warning message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void WarnFormat(string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the warning message.
-        /// </summary>
-        /// <param name="provider">The provider.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="args">The args.</param>
-        public void WarnFormat(IFormatProvider provider, string format, params object[] args)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the warning message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        public void WarnFormat(string format, object arg0, object arg1)
-        {
-
-        }
-
-        /// <summary>
-        /// Logs the warning message.
-        /// </summary>
-        /// <param name="format">The format.</param>
-        /// <param name="arg0">The arg0.</param>
-        /// <param name="arg1">The arg1.</param>
-        /// <param name="arg2">The arg2.</param>
-        public void WarnFormat(string format, object arg0, object arg1, object arg2)
-        {
-
-        }
-    }
 }

+ 1 - 27
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPLogFactory.cs

@@ -1,31 +1,5 @@
-using SuperSocket.SocketBase.Logging;
-using System.Collections.Generic;
+using System.Collections.Generic;
 
 namespace OCPPServer.SubProtocol
 {
-    /// <summary>
-    /// OCPP log factory
-    /// </summary>
-    public class OCPPLogFactory : LogFactoryBase
-    {
-        public OCPPLogFactory() : this("NLog.config")
-        {
-
-        }
-
-        public OCPPLogFactory(string log4netConfig)
-            : base(log4netConfig)
-        {
-            List<string> configlist = new List<string>();
-            configlist.Add(ConfigFile);
-            NLog.Config.XmlLoggingConfiguration.SetCandidateConfigFilePaths(configlist);
-        }
-
-        public override SuperSocket.SocketBase.Logging.ILog GetLog(string name)
-        {
-
-            return new OCPPLog(name);
-        }
-    }
-
 }

+ 35 - 0
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPSubCommandConverter.cs

@@ -0,0 +1,35 @@
+using SuperSocket.SocketBase.Protocol;
+using SuperWebSocket.SubProtocol;
+
+namespace OCPPServer.SubProtocol
+{
+    public class OCPPSubCommandParser : IRequestInfoParser<SubRequestInfo>
+    {
+        #region ISubProtocolCommandParser Members
+
+        /// <summary>
+        /// Parses the request info.
+        /// </summary>
+        /// <param name="source">The source.</param>
+        /// <returns></returns>
+        public SubRequestInfo ParseRequestInfo(string source)
+        {
+            var cmd = source.Trim();
+            int pos = cmd.IndexOf(',');
+            string name;
+
+            if (pos > 0)
+            {
+                name = cmd.Substring(pos - 1, 1);
+            }
+            else
+            {
+                name = "4";
+            }
+
+            return new SubRequestInfo(name, "", source);
+        }
+
+        #endregion ISubProtocolCommandParser Members
+    }
+}

+ 8 - 8
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPSubProtocol.cs

@@ -1,7 +1,7 @@
-using OCPPServer.Protocol;
+using Microsoft.Extensions.Logging;
+using OCPPServer.Protocol;
 using SuperSocket.Common;
 using SuperSocket.SocketBase;
-using SuperSocket.SocketBase.Logging;
 using SuperSocket.SocketBase.Protocol;
 using SuperWebSocket;
 using SuperWebSocket.Config;
@@ -90,7 +90,7 @@ namespace OCPPServer.SubProtocol
 
         }
 
-        public ILog Getmlog()
+        public ILogger Getmlog()
         {
             return getlog();
         }
@@ -109,7 +109,7 @@ namespace OCPPServer.SubProtocol
 
         private Dictionary<string, ISubCommand<TWebSocketSession>> m_CommandDict;
 
-        private ILog m_Logger;
+        private ILogger m_Logger;
 
         private SubCommandFilterAttribute[] m_GlobalFilters;
 
@@ -221,7 +221,7 @@ namespace OCPPServer.SubProtocol
             }
 
 
-            m_Logger.Debug(cmdbuilder.ToString());
+            m_Logger.LogDebug(cmdbuilder.ToString());
 #endif
 
             m_CommandDict = new Dictionary<string, ISubCommand<TWebSocketSession>>(subCommands.Count, StringComparer.OrdinalIgnoreCase);
@@ -252,12 +252,12 @@ namespace OCPPServer.SubProtocol
             }
             catch (Exception e)
             {
-                m_Logger.Error(e);
+                m_Logger.LogError(e,e.Message);
                 return false;
             }
         }
 
-        public ILog getlog()
+        public ILogger getlog()
         {
             return m_Logger;
         }
@@ -275,7 +275,7 @@ namespace OCPPServer.SubProtocol
 
 
 
-        public override bool Initialize(IAppServer appServer, SubProtocolConfig protocolConfig, ILog logger)
+        public override bool Initialize(IAppServer appServer, SubProtocolConfig protocolConfig, ILogger logger)
         {
             m_Logger = logger;
 

+ 39 - 19
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPWSServer.cs

@@ -1,6 +1,11 @@
 
 using EVCB_OCPP.Domain;
-using NLog;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Internal;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using MongoDB.Driver.Core.Servers;
 using OCPPPackage.Profiles;
 using SuperWebSocket;
 using SuperWebSocket.SubProtocol;
@@ -18,7 +23,10 @@ namespace OCPPServer.Protocol
     public class OCPPWSServer : WebSocketServer<ClientData>
     {
 
-        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
+        static private ILogger logger;
+        private readonly IConfiguration configuration;
+        private readonly IServiceProvider serviceProvider;
+
         /// <summary>
         /// 可允許連線Clinet數
         /// </summary>
@@ -33,27 +41,38 @@ namespace OCPPServer.Protocol
         /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
         /// </summary>
         /// <param name="subProtocols">The sub protocols.</param>
-        public OCPPWSServer(IEnumerable<ISubProtocol<ClientData>> subProtocols)
+        public OCPPWSServer(IEnumerable<ISubProtocol<ClientData>> subProtocols, IServiceProvider serviceProvider)
             : base(subProtocols)
         {
+            this.configuration = serviceProvider.GetService<IConfiguration>();
+            this.serviceProvider = serviceProvider;
+
+            logger = serviceProvider.GetService<ILogger<OCPPWSServer>>();
         }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
         /// </summary>
         /// <param name="subProtocol">The sub protocol.</param>
-        public OCPPWSServer(ISubProtocol<ClientData> subProtocol)
+        public OCPPWSServer(ISubProtocol<ClientData> subProtocol, IServiceProvider serviceProvider)
             : base(subProtocol)
         {
+            this.configuration = serviceProvider.GetService<IConfiguration>();
+            this.serviceProvider = serviceProvider;
+
+            logger = serviceProvider.GetService<ILogger<OCPPWSServer>>();
         }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="WebSocketServer"/> class.
         /// </summary>
-        public OCPPWSServer()
+        public OCPPWSServer(IServiceProvider serviceProvider)
             : base(new List<ISubProtocol<ClientData>>())
         {
+            this.configuration = serviceProvider.GetService<IConfiguration>();
+            this.serviceProvider = serviceProvider;
 
+            logger = serviceProvider.GetService<ILogger<OCPPWSServer>>();
         }
 
         protected override bool ValidateClientCertificate(ClientData session, object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
@@ -71,23 +90,24 @@ namespace OCPPServer.Protocol
             string authorizationKey = string.Empty;
             if (string.IsNullOrEmpty(session.Path))
             {
-                logger.Warn("===========================================");
-                logger.Warn("session.Path EMPTY");
-                logger.Warn("===========================================");
+                //logger.Log();
+                logger.LogWarning("===========================================");
+                logger.LogWarning("session.Path EMPTY");
+                logger.LogWarning("===========================================");
             }
 
             string[] words = session.Path.Split('/');
             session.ChargeBoxId = words.Last();
 
-            if (ConfigurationManager.AppSettings["MaintainMode"] == "1")
+            if (configuration["MaintainMode"] == "1")
             {
                 session.ChargeBoxId = session.ChargeBoxId + "_2";
             }
 
-            logger.Info(string.Format("ValidateHandshake: {0}", session.Path));
+            logger.LogInformation(string.Format("ValidateHandshake: {0}", session.Path));
             bool isExistedSN = false;
             bool authorizated = false;
-            using (var db = new MainDBContext())
+            using (var db = serviceProvider.GetService<IDbContextFactory<MainDBContext>>().CreateDbContext())
             {
                 var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).FirstOrDefault();
                 session.CustomerName = machine == null ? "Unknown" : db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefault();
@@ -107,11 +127,11 @@ namespace OCPPServer.Protocol
                     byte[] data = Encoding.UTF8.GetBytes(sb);
                     ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
 
-                    logger.Info(sb);
+                    logger.LogInformation(sb);
                     return false;
                 }
 
-                var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile)
+                var configVaule = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile)
                                   .Select(x => x.ConfigureSetting).FirstOrDefault();
                 int.TryParse(configVaule, out securityProfile);
 
@@ -133,7 +153,7 @@ namespace OCPPServer.Protocol
                 byte[] data = Encoding.UTF8.GetBytes(sb);
 
                 ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
-                logger.Info(sb);
+                logger.LogInformation(sb);
                 return false;
             }
 
@@ -147,10 +167,10 @@ namespace OCPPServer.Protocol
                 if (session.Items.ContainsKey("Authorization") || session.Items.ContainsKey("authorization"))
                 {
 
-                    using (var db = new MainDBContext())
+                    using (var db = serviceProvider.GetService<IDbContextFactory<MainDBContext>>().CreateDbContext())
                     {
 
-                        authorizationKey = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey)
+                        authorizationKey = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey)
                                           .Select(x => x.ConfigureSetting).FirstOrDefault();
 
 
@@ -160,14 +180,14 @@ namespace OCPPServer.Protocol
                             securityProfile = 0;
                         }
                     }
-                    logger.Info("***********Authorization   ");
+                    logger.LogInformation("***********Authorization   ");
 
                     if (!string.IsNullOrEmpty(authorizationKey))
                     {
                         string base64Encoded = session.Items.ContainsKey("Authorization") ? session.Items["Authorization"].ToString().Replace("Basic ", "") : session.Items["authorization"].ToString().Replace("Basic ", "");
                         byte[] data = Convert.FromBase64String(base64Encoded);
                         string[] base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(data).Split(':');
-                        logger.Info("***********Authorization   " + System.Text.ASCIIEncoding.ASCII.GetString(data));
+                        logger.LogInformation("***********Authorization   " + System.Text.ASCIIEncoding.ASCII.GetString(data));
                         if (base64Decoded.Count() == 2 && base64Decoded[0] == session.ChargeBoxId && base64Decoded[1] == authorizationKey)
                         {
                             authorizated = true;
@@ -199,7 +219,7 @@ namespace OCPPServer.Protocol
                     byte[] data = Encoding.UTF8.GetBytes(sb);
 
                     ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
-                    logger.Info(sb);
+                    logger.LogInformation(sb);
                     return false;
                 }
             }

+ 1449 - 0
EVCB_OCPP.WSServer/UpgradeReport.sarif

@@ -0,0 +1,1449 @@
+{
+  "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
+  "version": "2.1.0",
+  "runs": [
+    {
+      "tool": {
+        "driver": {
+          "name": "Back up project",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Backup.BackupStep",
+              "fullDescription": {
+                "text": "Project backed up to D:\\RobertProject\\Research\\Docker\\OCPP後台20221130\\187_OCPPServer_Master\\EVCB_OCPP.WSServer.backup"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Backup.BackupStep",
+          "message": {
+            "text": "Complete: Project backed up to D:\\RobertProject\\Research\\Docker\\OCPP後台20221130\\187_OCPPServer_Master\\EVCB_OCPP.WSServer.backup"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer.backup"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Convert project file to SDK style",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.ProjectFormat.TryConvertProjectConverterStep",
+              "fullDescription": {
+                "text": "Project file converted successfully! The project may require additional changes to build successfully against the new .NET target."
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.ProjectFormat.TryConvertProjectConverterStep",
+          "message": {
+            "text": "Complete: Project file converted successfully! The project may require additional changes to build successfully against the new .NET target."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.ComponentModel.Annotations'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.ComponentModel.Annotations'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.ComponentModel.Annotations'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove reference 'System.Configuration'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.Reference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove reference 'System.Configuration'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.Reference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove reference 'System.Configuration'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove reference 'System.ServiceModel'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.Reference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove reference 'System.ServiceModel'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.Reference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove reference 'System.ServiceModel'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'System.Configuration.ConfigurationManager'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'System.Configuration.ConfigurationManager'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'System.Configuration.ConfigurationManager'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'System.ServiceModel.Primitives'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'System.ServiceModel.Primitives'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'System.ServiceModel.Primitives'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'System.ServiceModel.Http'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'System.ServiceModel.Http'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'System.ServiceModel.Http'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'System.ServiceModel.Duplex'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'System.ServiceModel.Duplex'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'System.ServiceModel.Duplex'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'System.ServiceModel.NetTcp'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'System.ServiceModel.NetTcp'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'System.ServiceModel.NetTcp'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'System.ServiceModel.Security'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'System.ServiceModel.Security'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'System.ServiceModel.Security'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'System.ServiceModel.Federation'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'System.ServiceModel.Federation'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'System.ServiceModel.Federation'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Bcl.AsyncInterfaces'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Bcl.AsyncInterfaces'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Bcl.AsyncInterfaces'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.Configuration'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.Configuration'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.Configuration'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.Configuration.Abstractions'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.Configuration.Abstractions'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.Configuration.Abstractions'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.Configuration.Binder'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.Configuration.Binder'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.Configuration.Binder'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.DependencyInjection'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.DependencyInjection'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.DependencyInjection'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.DependencyInjection.Abstractions'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.DependencyInjection.Abstractions'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.DependencyInjection.Abstractions'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.Logging'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.Logging'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.Logging'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.Logging.Abstractions'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.Logging.Abstractions'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.Logging.Abstractions'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.Options'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.Options'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.Options'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.Extensions.Primitives'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.Extensions.Primitives'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.Extensions.Primitives'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'NLog'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'NLog'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'NLog'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'NLog.Schema'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'NLog.Schema'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'NLog.Schema'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.Buffers'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.Buffers'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.Buffers'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.Memory'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.Memory'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.Memory'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.Numerics.Vectors'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.Numerics.Vectors'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.Numerics.Vectors'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.Runtime.CompilerServices.Unsafe'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.Runtime.CompilerServices.Unsafe'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.Runtime.CompilerServices.Unsafe'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.Threading.Tasks.Extensions'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.Threading.Tasks.Extensions'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.Threading.Tasks.Extensions'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.ServiceModel.Primitives'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.ServiceModel.Primitives'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.ServiceModel.Primitives'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.ServiceModel.Http'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.ServiceModel.Http'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.ServiceModel.Http'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'System.ServiceModel.Security'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'System.ServiceModel.Security'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'System.ServiceModel.Security'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Update TFM",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.ProjectFormat.SetTFMStep",
+              "fullDescription": {
+                "text": "Updated TFM to net7.0"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.ProjectFormat.SetTFMStep",
+          "message": {
+            "text": "Complete: Updated TFM to net7.0"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'EntityFramework'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'EntityFramework'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'EntityFramework'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'log4net'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'log4net'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'log4net'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'EntityFramework'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'EntityFramework'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'EntityFramework'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Add package 'log4net'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Add package 'log4net'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Add package 'log4net'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    },
+    {
+      "tool": {
+        "driver": {
+          "name": "Remove package 'Microsoft.CSharp'",
+          "semanticVersion": "",
+          "informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
+          "rules": [
+            {
+              "id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+              "fullDescription": {
+                "text": "Remove package 'Microsoft.CSharp'"
+              },
+              "helpUri": "about:blank"
+            }
+          ]
+        }
+      },
+      "results": [
+        {
+          "ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
+          "message": {
+            "text": "Complete: Remove package 'Microsoft.CSharp'"
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "file:///D:/RobertProject/Research/Docker/OCPP%E5%BE%8C%E5%8F%B020221130/187_OCPPServer_Master/EVCB_OCPP.WSServer/EVCB_OCPP.WSServer.csproj"
+                },
+                "region": {}
+              }
+            }
+          ]
+        }
+      ],
+      "columnKind": "utf16CodeUnits"
+    }
+  ]
+}

+ 93 - 0
EVCB_OCPP.WSServer/appsettings.json

@@ -0,0 +1,93 @@
+{
+  "LocalAuthAPI": "",
+  "OCPP20_WSUrl": "ws://ocpp.phihong.com.tw:5004",
+  "OCPP20_WSSUrl": "ws://ocpp.phihong.com.tw:5004",
+  "MaintainMode": 0,
+  "superSocket": {
+    "Servers": [
+      {
+        "Name": "SuperWebSocket",
+        "serverTypeName": "SuperWebSocket",
+        "Certificate": {
+          "filePath": "localhost.pfx",
+          "password": "supersocket",
+          "storeName": "My",
+          "thumbprint": "‎3f07fb28c158843209db8f51bfe748dbe9f52399",
+          "storeLocation": "LocalMachine",
+          "clientCertificateRequired": "false",
+          "keyStorageFlags": "Exportable"
+        }
+      }
+    ]
+  },
+  "SuperSocketServerCertificate": {
+    "filePath": "localhost.pfx",
+    "password": "supersocket",
+    "storeName": "My",
+    "thumbprint": "‎3f07fb28c158843209db8f51bfe748dbe9f52399",
+    "storeLocation": "LocalMachine",
+    "clientCertificateRequired": "false",
+    "keyStorageFlags": "Exportable"
+  },
+  "NLog": {
+    "targets": {
+      "f": {
+        "type": "File",
+        "fileName": "${basedir}/logs/${shortdate}.log",
+        "layout": "${longdate} ${uppercase:${level}} ${message}"
+      },
+      "ws": {
+        "type": "File",
+        "fileName": "${basedir}/logs/WS_${shortdate}.log",
+        "layout": "${longdate} ${uppercase:${level}} ${message}"
+      },
+      "Console": {
+        "type": "Console",
+        "layout": "${longdate} ${uppercase:${level}} ${message}"
+      },
+      "auth": {
+        "type": "File",
+        "fileName": "${basedir}/logs/Auth_${shortdate}.log",
+        "layout": "${longdate} ${callsite} ${uppercase:${level}} ${message}"
+      }
+    },
+    "rules": [
+      {
+        "ruleName": "OCPPServer",
+        "logger": "OCPPServer.*",
+        "minLevel": "Info",
+        "writeTo": "ws"
+      },
+      {
+        "ruleName": "SuperWebSocket",
+        "logger": "SuperWebSocket.*",
+        "minLevel": "Info",
+        "writeTo": "ws"
+      },
+      {
+        "ruleName": "OuterBusinessService",
+        "logger": "EVCB_OCPP.WSServer.Service.OuterBusinessService",
+        "level": "Info",
+        "writeTo": "auth"
+      },
+      {
+        "ruleName": "FileLog",
+        "logger": "EVCB_OCPP.*",
+        "minLevel": "Debug",
+        "writeTo": "f"
+      },
+      {
+        "ruleName": "ConsoleLog",
+        "logger": "EVCB_OCPP.*",
+        "minlevel": "Trace",
+        "writeTo": "console"
+      }
+    ]
+  },
+  "ConnectionStrings": {
+    "ConnectionLogDBContext": "data source=172.1.0.131\\DEV_OCPP_PORTAL;initial catalog=Docker_ConnectionLog;;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=True;",
+    "MainDBContext": "data source=172.1.0.131\\DEV_OCPP_PORTAL;initial catalog=Docker_Main;;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=True;",
+    "MeterValueDBContext": "data source=172.1.0.131\\DEV_OCPP_PORTAL;initial catalog=Docker_MeterValue;;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=True;",
+    "WebDBContext": "data source=172.1.0.131\\DEV_OCPP_PORTAL;initial catalog=Docker_Web;;persist security info=True;user id=sa;password=Ph0930118811;MultipleActiveResultSets=True;App=EntityFramework;TrustServerCertificate=True;"
+  }
+}

+ 373 - 0
SocketBase.backup/AppServer.cs

@@ -0,0 +1,373 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using SuperSocket.Common;
+using SuperSocket.SocketBase.Command;
+using SuperSocket.SocketBase.Config;
+using SuperSocket.SocketBase.Protocol;
+using SuperSocket.SocketBase.Security;
+
+namespace SuperSocket.SocketBase
+{
+    /// <summary>
+    /// AppServer class
+    /// </summary>
+    public class AppServer : AppServer<AppSession>
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppServer"/> class.
+        /// </summary>
+        public AppServer()
+            : base()
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppServer"/> class.
+        /// </summary>
+        /// <param name="receiveFilterFactory">The Receive filter factory.</param>
+        public AppServer(IReceiveFilterFactory<StringRequestInfo> receiveFilterFactory)
+            : base(receiveFilterFactory)
+        {
+
+        }
+    }
+
+    /// <summary>
+    /// AppServer class
+    /// </summary>
+    /// <typeparam name="TAppSession">The type of the app session.</typeparam>
+    public class AppServer<TAppSession> : AppServer<TAppSession, StringRequestInfo>
+        where TAppSession : AppSession<TAppSession, StringRequestInfo>, IAppSession, new()
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppServer&lt;TAppSession&gt;"/> class.
+        /// </summary>
+        public AppServer()
+            : base()
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppServer&lt;TAppSession&gt;"/> class.
+        /// </summary>
+        /// <param name="receiveFilterFactory">The Receive filter factory.</param>
+        public AppServer(IReceiveFilterFactory<StringRequestInfo> receiveFilterFactory)
+            : base(receiveFilterFactory)
+        {
+
+        }
+
+        internal override IReceiveFilterFactory<StringRequestInfo> CreateDefaultReceiveFilterFactory()
+        {
+            return new CommandLineReceiveFilterFactory(TextEncoding);
+        }
+    }
+
+
+    /// <summary>
+    /// AppServer basic class
+    /// </summary>
+    /// <typeparam name="TAppSession">The type of the app session.</typeparam>
+    /// <typeparam name="TRequestInfo">The type of the request info.</typeparam>
+    public abstract class AppServer<TAppSession, TRequestInfo> : AppServerBase<TAppSession, TRequestInfo>
+        where TRequestInfo : class, IRequestInfo
+        where TAppSession : AppSession<TAppSession, TRequestInfo>, IAppSession, new()
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppServer&lt;TAppSession, TRequestInfo&gt;"/> class.
+        /// </summary>
+        public AppServer()
+            : base()
+        {
+            
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppServer&lt;TAppSession, TRequestInfo&gt;"/> class.
+        /// </summary>
+        /// <param name="protocol">The protocol.</param>
+        protected AppServer(IReceiveFilterFactory<TRequestInfo> protocol)
+            : base(protocol)
+        {
+   
+        }
+
+        internal override IReceiveFilterFactory<TRequestInfo> CreateDefaultReceiveFilterFactory()
+        {
+            return null;
+        }
+
+        /// <summary>
+        /// Starts this AppServer instance.
+        /// </summary>
+        /// <returns></returns>
+        public override bool Start()
+        {
+            if (!base.Start())
+                return false;
+
+            if (!Config.DisableSessionSnapshot)
+                StartSessionSnapshotTimer();
+
+            if (Config.ClearIdleSession)
+                StartClearSessionTimer();
+
+            return true;
+        }
+
+        private ConcurrentDictionary<string, TAppSession> m_SessionDict = new ConcurrentDictionary<string, TAppSession>(StringComparer.OrdinalIgnoreCase);
+
+        /// <summary>
+        /// Registers the session into the session container.
+        /// </summary>
+        /// <param name="sessionID">The session ID.</param>
+        /// <param name="appSession">The app session.</param>
+        /// <returns></returns>
+        protected override bool RegisterSession(string sessionID, TAppSession appSession)
+        {
+            if (m_SessionDict.TryAdd(sessionID, appSession))
+                return true;
+
+            if (Logger.IsErrorEnabled)
+                Logger.Error(appSession, "The session is refused because the it's ID already exists!");
+
+            return false;
+        }
+
+        /// <summary>
+        /// Gets the app session by ID.
+        /// </summary>
+        /// <param name="sessionID">The session ID.</param>
+        /// <returns></returns>
+        [Obsolete("Use the method GetSessionByID instead")]
+        public TAppSession GetAppSessionByID(string sessionID)
+        {
+            return GetSessionByID(sessionID);
+        }
+
+        /// <summary>
+        /// Gets the app session by ID.
+        /// </summary>
+        /// <param name="sessionID">The session ID.</param>
+        /// <returns></returns>
+        public override TAppSession GetSessionByID(string sessionID)
+        {
+            if (string.IsNullOrEmpty(sessionID))
+                return NullAppSession;
+
+            TAppSession targetSession;
+            m_SessionDict.TryGetValue(sessionID, out targetSession);
+            return targetSession;
+        }
+
+        /// <summary>
+        /// Called when [socket session closed].
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="reason">The reason.</param>
+        protected override void OnSessionClosed(TAppSession session, CloseReason reason)
+        {
+            string sessionID = session.SessionID;
+
+            if (!string.IsNullOrEmpty(sessionID))
+            {
+                TAppSession removedSession;
+                if (!m_SessionDict.TryRemove(sessionID, out removedSession))
+                {
+                    if (Logger.IsErrorEnabled)
+                        Logger.Error(session, "Failed to remove this session, Because it has't been in session container!");
+                }
+            }
+
+            base.OnSessionClosed(session, reason);
+        }
+
+        /// <summary>
+        /// Gets the total session count.
+        /// </summary>
+        public override int SessionCount
+        {
+            get
+            {
+                return m_SessionDict.Count;
+            }
+        }
+
+        #region Clear idle sessions
+
+        private System.Threading.Timer m_ClearIdleSessionTimer = null;
+
+        private void StartClearSessionTimer()
+        {
+            int interval = Config.ClearIdleSessionInterval * 1000;//in milliseconds
+            m_ClearIdleSessionTimer = new System.Threading.Timer(ClearIdleSession, new object(), interval, interval);
+        }
+
+        /// <summary>
+        /// Clears the idle session.
+        /// </summary>
+        /// <param name="state">The state.</param>
+        private void ClearIdleSession(object state)
+        {
+            if (Monitor.TryEnter(state))
+            {
+                try
+                {
+                    var sessionSource = SessionSource;
+
+                    if (sessionSource == null)
+                        return;
+
+                    DateTime now = DateTime.Now;
+                    DateTime timeOut = now.AddSeconds(0 - Config.IdleSessionTimeOut);
+
+                    var timeOutSessions = sessionSource.Where(s => s.Value.LastActiveTime <= timeOut).Select(s => s.Value);
+
+                    System.Threading.Tasks.Parallel.ForEach(timeOutSessions, s =>
+                        {
+                            if (Logger.IsInfoEnabled)
+                                logger.LogInformation(s, string.Format("The session will be closed for {0} timeout, the session start time: {1}, last active time: {2}!", now.Subtract(s.LastActiveTime).TotalSeconds, s.StartTime, s.LastActiveTime));
+                            s.Close(CloseReason.TimeOut);
+                        });
+                }
+                catch (Exception e)
+                {
+                    if(Logger.IsErrorEnabled)
+                        Logger.Error("Clear idle session error!", e);
+                }
+                finally
+                {
+                    Monitor.Exit(state);
+                }
+            }
+        }
+
+        private KeyValuePair<string, TAppSession>[] SessionSource
+        {
+            get
+            {
+                if (Config.DisableSessionSnapshot)
+                    return m_SessionDict.ToArray();
+                else
+                    return m_SessionsSnapshot;
+            }
+        }
+
+        #endregion
+
+        #region Take session snapshot
+
+        private System.Threading.Timer m_SessionSnapshotTimer = null;
+
+        private KeyValuePair<string, TAppSession>[] m_SessionsSnapshot = new KeyValuePair<string, TAppSession>[0];
+
+        private void StartSessionSnapshotTimer()
+        {
+            int interval = Math.Max(Config.SessionSnapshotInterval, 1) * 1000;//in milliseconds
+            m_SessionSnapshotTimer = new System.Threading.Timer(TakeSessionSnapshot, new object(), interval, interval);
+        }
+
+        private void TakeSessionSnapshot(object state)
+        {
+            if (Monitor.TryEnter(state))
+            {
+                Interlocked.Exchange(ref m_SessionsSnapshot, m_SessionDict.ToArray());
+                Monitor.Exit(state);
+            }
+        }
+
+        #endregion
+
+        #region Search session utils
+
+        /// <summary>
+        /// Gets the matched sessions from sessions snapshot.
+        /// </summary>
+        /// <param name="critera">The prediction critera.</param>
+        /// <returns></returns>
+        public override IEnumerable<TAppSession> GetSessions(Func<TAppSession, bool> critera)
+        {
+            var sessionSource = SessionSource;
+
+            if (sessionSource == null)
+                return null;
+
+            return sessionSource.Select(p => p.Value).Where(critera);
+        }
+
+        /// <summary>
+        /// Gets all sessions in sessions snapshot.
+        /// </summary>
+        /// <returns></returns>
+        public override IEnumerable<TAppSession> GetAllSessions()
+        {
+            var sessionSource = SessionSource;
+
+            if (sessionSource == null)
+                return null;
+
+            return sessionSource.Select(p => p.Value);
+        }
+
+        /// <summary>
+        /// Stops this instance.
+        /// </summary>
+        public override void Stop()
+        {
+            base.Stop();
+
+            if (m_SessionSnapshotTimer != null)
+            {
+                m_SessionSnapshotTimer.Change(Timeout.Infinite, Timeout.Infinite);
+                m_SessionSnapshotTimer.Dispose();
+                m_SessionSnapshotTimer = null;
+            }
+
+            if (m_ClearIdleSessionTimer != null)
+            {
+                m_ClearIdleSessionTimer.Change(Timeout.Infinite, Timeout.Infinite);
+                m_ClearIdleSessionTimer.Dispose();
+                m_ClearIdleSessionTimer = null;
+            }
+
+            m_SessionsSnapshot = null;
+
+            var sessions = m_SessionDict.ToArray();
+
+            if (sessions.Length > 0)
+            {
+                var tasks = new Task[sessions.Length];
+
+                for (var i = 0; i < tasks.Length; i++)
+                {
+                    tasks[i] = Task.Factory.StartNew((s) =>
+                    {
+                        var session = s as TAppSession;
+
+                        if (session != null)
+                        {
+                            session.Close(CloseReason.ServerShutdown);
+                        }
+
+                    }, sessions[i].Value);
+                }
+
+                Task.WaitAll(tasks);
+            }
+        }
+
+        #endregion
+    }
+}

+ 159 - 0
SocketBase.backup/AppServerBase.ConfigHotUpdate.cs

@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Configuration;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SuperSocket.Common;
+using SuperSocket.SocketBase.Config;
+using SuperSocket.SocketBase.Protocol;
+
+namespace SuperSocket.SocketBase
+{
+    interface IConfigValueChangeNotifier
+    {
+        bool Notify(string newValue);
+    }
+
+    class ConfigValueChangeNotifier : IConfigValueChangeNotifier
+    {
+        Func<string, bool> m_Handler;
+
+        public ConfigValueChangeNotifier(Func<string, bool> handler)
+        {
+            m_Handler = handler;
+        }
+
+        public bool Notify(string newValue)
+        {
+            return m_Handler(newValue);
+        }
+    }
+    class ConfigValueChangeNotifier<TConfigOption> : IConfigValueChangeNotifier
+        where TConfigOption : ConfigurationElement, new()
+    {
+        Func<TConfigOption, bool> m_Handler;
+
+        public ConfigValueChangeNotifier(Func<TConfigOption, bool> handler)
+        {
+            m_Handler = handler;
+        }
+        public bool Notify(string newValue)
+        {
+            if (string.IsNullOrEmpty(newValue))
+                return m_Handler(default(TConfigOption));
+            else
+                return m_Handler(ConfigurationExtension.DeserializeChildConfig<TConfigOption>(newValue));
+        }
+    }
+
+    public abstract partial class AppServerBase<TAppSession, TRequestInfo>
+        where TRequestInfo : class, IRequestInfo
+        where TAppSession : AppSession<TAppSession, TRequestInfo>, IAppSession, new()
+    {
+        private Dictionary<string, IConfigValueChangeNotifier> m_ConfigUpdatedNotifiers = new Dictionary<string, IConfigValueChangeNotifier>(StringComparer.OrdinalIgnoreCase);
+
+        /// <summary>
+        /// Registers the configuration option value handler, it is used for reading configuration value and reload it after the configuration is changed;
+        /// </summary>
+        /// <typeparam name="TConfigOption">The type of the configuration option.</typeparam>
+        /// <param name="config">The server configuration.</param>
+        /// <param name="name">The changed config option's name.</param>
+        /// <param name="handler">The handler.</param>
+        protected bool RegisterConfigHandler<TConfigOption>(IServerConfig config, string name, Func<TConfigOption, bool> handler)
+            where TConfigOption : ConfigurationElement, new()
+        {
+            var notifier = new ConfigValueChangeNotifier<TConfigOption>(handler);
+            m_ConfigUpdatedNotifiers.Add(name, notifier);
+            return notifier.Notify(config.Options.GetValue(name));
+        }
+
+        /// <summary>
+        /// Registers the configuration option value handler, it is used for reading configuration value and reload it after the configuration is changed;
+        /// </summary>
+        /// <param name="config">The server configuration.</param>
+        /// <param name="name">The changed config option name.</param>
+        /// <param name="handler">The handler.</param>
+        protected bool RegisterConfigHandler(IServerConfig config, string name, Func<string, bool> handler)
+        {
+            var notifier = new ConfigValueChangeNotifier(handler);
+            m_ConfigUpdatedNotifiers.Add(name, notifier);
+            return notifier.Notify(config.OptionElements.GetValue(name));
+        }
+
+        int CheckConfigOptionsChange(NameValueCollection oldOptions, NameValueCollection newOptions)
+        {
+            var changed = 0;
+
+            if (oldOptions == null && newOptions == null)
+                return changed;
+
+            var oldOptionsDict = oldOptions == null
+                    ? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
+                    : Enumerable.Range(0, oldOptions.Count)
+                        .Select(i => new KeyValuePair<string, string>(oldOptions.GetKey(i), oldOptions.Get(i)))
+                        .ToDictionary(p => p.Key, p => p.Value, StringComparer.OrdinalIgnoreCase);
+
+            foreach(var key in newOptions.AllKeys)
+            {
+                var newValue = newOptions[key];
+
+                var oldValue = string.Empty;
+
+                if (oldOptionsDict.TryGetValue(key, out oldValue))
+                    oldOptionsDict.Remove(key);
+
+                if (string.Compare(newValue, oldValue) == 0)
+                    continue;
+
+                NotifyConfigUpdated(key, newValue);
+                changed++;
+            }
+
+            if (oldOptionsDict.Count > 0)
+            {
+                foreach (var p in oldOptionsDict)
+                {
+                    NotifyConfigUpdated(p.Key, string.Empty);
+                    changed++;
+                }
+            }
+
+            return changed;
+        }
+
+        private void NotifyConfigUpdated(string key, string newValue)
+        {
+            IConfigValueChangeNotifier notifier;
+
+            if (!m_ConfigUpdatedNotifiers.TryGetValue(key, out notifier))
+                return;
+
+            try
+            {
+                if (!notifier.Notify(newValue))
+                    throw new Exception("returned false in the handling logic");
+            }
+            catch (Exception e)
+            {
+                Logger.Error("Failed to handle custom configuration reading, name: " + key, e);
+            }
+        }
+
+        void IWorkItemBase.ReportPotentialConfigChange(IServerConfig config)
+        {
+            var oldConfig = this.Config;
+
+            CheckConfigOptionsChange(oldConfig.Options, config.Options);
+            CheckConfigOptionsChange(oldConfig.OptionElements, config.OptionElements);
+
+            var updatableConfig = oldConfig as ServerConfig;
+
+            if (updatableConfig == null)
+                return;
+
+            config.CopyPropertiesTo(p => p.GetCustomAttributes(typeof(HotUpdateAttribute), true).Length > 0, updatableConfig);
+        }
+    }
+}

+ 51 - 0
SocketBase.backup/AppServerBase.Net45.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SuperSocket.SocketBase.Config;
+using SuperSocket.SocketBase.Protocol;
+
+namespace SuperSocket.SocketBase
+{
+    public abstract partial class AppServerBase<TAppSession, TRequestInfo>
+        where TRequestInfo : class, IRequestInfo
+        where TAppSession : AppSession<TAppSession, TRequestInfo>, IAppSession, new()
+    {
+        partial void SetDefaultCulture(IRootConfig rootConfig, IServerConfig config)
+        {
+            var defaultCulture = config.DefaultCulture;
+            
+            //default culture has been set for this server instance
+            if (!string.IsNullOrEmpty(defaultCulture))
+            {
+                if (rootConfig.Isolation == IsolationMode.None)
+                {
+                    Logger.WarnFormat("The default culture '{0}' cannot be set, because you cannot set default culture for one server instance if the Isolation is None!");
+                    return;
+                }
+            }
+            else if(!string.IsNullOrEmpty(rootConfig.DefaultCulture))
+            {
+                defaultCulture = rootConfig.DefaultCulture;
+
+                //Needn't set default culture in this case, because it has been set in the bootstrap
+                if (rootConfig.Isolation == IsolationMode.None)
+                    return;
+            }
+
+            if (string.IsNullOrEmpty(defaultCulture))
+                return;
+
+            try
+            {
+                CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(defaultCulture);
+            }
+            catch (Exception e)
+            {
+                Logger.Error(string.Format("Failed to set default culture '{0}'.", defaultCulture), e);
+            }
+        }
+    }
+}

+ 1723 - 0
SocketBase.backup/AppServerBase.cs

@@ -0,0 +1,1723 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Security;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using SuperSocket.Common;
+using SuperSocket.SocketBase.Command;
+using SuperSocket.SocketBase.Config;
+using SuperSocket.SocketBase.Logging;
+using SuperSocket.SocketBase.Metadata;
+using SuperSocket.SocketBase.Protocol;
+using SuperSocket.SocketBase.Provider;
+using SuperSocket.SocketBase.Security;
+
+namespace SuperSocket.SocketBase
+{
+    /// <summary>
+    /// AppServer base class
+    /// </summary>
+    /// <typeparam name="TAppSession">The type of the app session.</typeparam>
+    /// <typeparam name="TRequestInfo">The type of the request info.</typeparam>
+    [AppServerMetadataType(typeof(DefaultAppServerMetadata))]
+	public abstract partial class AppServerBase<TAppSession, TRequestInfo> : IAppServer<TAppSession, TRequestInfo>, IRawDataProcessor<TAppSession>, IRequestHandler<TRequestInfo>, ISocketServerAccessor, IStatusInfoSource, IRemoteCertificateValidator, IActiveConnector, ISystemEndPoint, IDisposable
+        where TRequestInfo : class, IRequestInfo
+        where TAppSession : AppSession<TAppSession, TRequestInfo>, IAppSession, new()
+    {
+        /// <summary>
+        /// Null appSession instance
+        /// </summary>
+        protected readonly TAppSession NullAppSession = default(TAppSession);
+
+        /// <summary>
+        /// Gets the server's config.
+        /// </summary>
+        public IServerConfig Config { get; private set; }
+
+        //Server instance name
+        private string m_Name;
+
+        /// <summary>
+        /// the current state's code
+        /// </summary>
+        private int m_StateCode = ServerStateConst.NotInitialized;
+
+        /// <summary>
+        /// Gets the current state of the work item.
+        /// </summary>
+        /// <value>
+        /// The state.
+        /// </value>
+        public ServerState State
+        {
+            get
+            {
+                return (ServerState)m_StateCode;
+            }
+        }
+
+        /// <summary>
+        /// Gets the certificate of current server.
+        /// </summary>
+        public X509Certificate Certificate { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the receive filter factory.
+        /// </summary>
+        /// <value>
+        /// The receive filter factory.
+        /// </value>
+        public virtual IReceiveFilterFactory<TRequestInfo> ReceiveFilterFactory { get; protected set; }
+
+        /// <summary>
+        /// Gets the Receive filter factory.
+        /// </summary>
+        object IAppServer.ReceiveFilterFactory
+        {
+            get { return this.ReceiveFilterFactory; }
+        }
+
+        private List<ICommandLoader<ICommand<TAppSession, TRequestInfo>>> m_CommandLoaders = new List<ICommandLoader<ICommand<TAppSession, TRequestInfo>>>();
+
+        private Dictionary<string, CommandInfo<ICommand<TAppSession, TRequestInfo>>> m_CommandContainer;
+
+        private CommandFilterAttribute[] m_GlobalCommandFilters;
+
+        private ISocketServerFactory m_SocketServerFactory;
+
+        /// <summary>
+        /// Gets the basic transfer layer security protocol.
+        /// </summary>
+        public SslProtocols BasicSecurity { get; private set; }
+
+        /// <summary>
+        /// Gets the root config.
+        /// </summary>
+        protected IRootConfig RootConfig { get; private set; }
+
+        /// <summary>
+        /// Gets the logger assosiated with this object.
+        /// </summary>
+        public ILog Logger { get; private set; }
+
+        /// <summary>
+        /// Gets the bootstrap of this appServer instance.
+        /// </summary>
+        protected IBootstrap Bootstrap { get; private set; }
+
+        private static bool m_ThreadPoolConfigured = false;
+
+        private List<IConnectionFilter> m_ConnectionFilters;
+
+        private long m_TotalHandledRequests = 0;
+
+        /// <summary>
+        /// Gets the total handled requests number.
+        /// </summary>
+        protected long TotalHandledRequests
+        {
+            get { return m_TotalHandledRequests; }
+        }
+
+        private ListenerInfo[] m_Listeners;
+
+        /// <summary>
+        /// Gets or sets the listeners inforamtion.
+        /// </summary>
+        /// <value>
+        /// The listeners.
+        /// </value>
+        public ListenerInfo[] Listeners
+        {
+            get { return m_Listeners; }
+        }
+
+        /// <summary>
+        /// Gets the started time of this server instance.
+        /// </summary>
+        /// <value>
+        /// The started time.
+        /// </value>
+        public DateTime StartedTime { get; private set; }
+
+
+        /// <summary>
+        /// Gets or sets the log factory.
+        /// </summary>
+        /// <value>
+        /// The log factory.
+        /// </value>
+        public ILogFactory LogFactory { get; private set; }
+
+
+        /// <summary>
+        /// Gets the default text encoding.
+        /// </summary>
+        /// <value>
+        /// The text encoding.
+        /// </value>
+        public Encoding TextEncoding { get; private set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppServerBase&lt;TAppSession, TRequestInfo&gt;"/> class.
+        /// </summary>
+        public AppServerBase()
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppServerBase&lt;TAppSession, TRequestInfo&gt;"/> class.
+        /// </summary>
+        /// <param name="receiveFilterFactory">The Receive filter factory.</param>
+        public AppServerBase(IReceiveFilterFactory<TRequestInfo> receiveFilterFactory)
+        {
+            this.ReceiveFilterFactory = receiveFilterFactory;
+        }
+
+        /// <summary>
+        /// Gets the filter attributes.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns></returns>
+        internal static CommandFilterAttribute[] GetCommandFilterAttributes(Type type)
+        {
+            var attrs = type.GetCustomAttributes(true);
+            return attrs.OfType<CommandFilterAttribute>().ToArray();
+        }
+
+        /// <summary>
+        /// Setups the command into command dictionary
+        /// </summary>
+        /// <param name="discoveredCommands">The discovered commands.</param>
+        /// <returns></returns>
+        protected virtual bool SetupCommands(Dictionary<string, ICommand<TAppSession, TRequestInfo>> discoveredCommands)
+        {
+            foreach (var loader in m_CommandLoaders)
+            {
+                loader.Error += new EventHandler<ErrorEventArgs>(CommandLoaderOnError);
+                loader.Updated += new EventHandler<CommandUpdateEventArgs<ICommand<TAppSession, TRequestInfo>>>(CommandLoaderOnCommandsUpdated);
+
+                if (!loader.Initialize(RootConfig, this))
+                {
+                    if (Logger.IsErrorEnabled)
+                        Logger.ErrorFormat("Failed initialize the command loader {0}.", loader.ToString());
+                    return false;
+                }
+
+                IEnumerable<ICommand<TAppSession, TRequestInfo>> commands;
+                if (!loader.TryLoadCommands(out commands))
+                {
+                    if (Logger.IsErrorEnabled)
+                        Logger.ErrorFormat("Failed load commands from the command loader {0}.", loader.ToString());
+                    return false;
+                }
+
+                if (commands != null && commands.Any())
+                {
+                    foreach (var c in commands)
+                    {
+                        if (discoveredCommands.ContainsKey(c.Name))
+                        {
+                            if (Logger.IsErrorEnabled)
+                                Logger.Error("Duplicated name command has been found! Command name: " + c.Name);
+                            return false;
+                        }
+
+                        var castedCommand = c as ICommand<TAppSession, TRequestInfo>;
+
+                        if (castedCommand == null)
+                        {
+                            if (Logger.IsErrorEnabled)
+                                Logger.Error("Invalid command has been found! Command name: " + c.Name);
+                            return false;
+                        }
+
+                        if (Logger.IsDebugEnabled)
+                            logger.LogDebugFormat("The command {0}({1}) has been discovered", castedCommand.Name, castedCommand.ToString());
+
+                        discoveredCommands.Add(c.Name, castedCommand);
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        void CommandLoaderOnCommandsUpdated(object sender, CommandUpdateEventArgs<ICommand<TAppSession, TRequestInfo>> e)
+        {
+            var workingDict = m_CommandContainer.Values.ToDictionary(c => c.Command.Name, c => c.Command, StringComparer.OrdinalIgnoreCase);
+            var updatedCommands = 0;
+
+            foreach (var c in e.Commands)
+            {
+                if (c == null)
+                    continue;
+
+                if (c.UpdateAction == CommandUpdateAction.Remove)
+                {
+                    workingDict.Remove(c.Command.Name);
+                    if (Logger.IsInfoEnabled)
+                        logger.LogInformation(Format("The command '{0}' has been removed from this server!", c.Command.Name);
+                }
+                else if (c.UpdateAction == CommandUpdateAction.Add)
+                {
+                    workingDict.Add(c.Command.Name, c.Command);
+                    if (Logger.IsInfoEnabled)
+                        logger.LogInformation(Format("The command '{0}' has been added into this server!", c.Command.Name);
+                }
+                else
+                {
+                    workingDict[c.Command.Name] = c.Command;
+                    if (Logger.IsInfoEnabled)
+                        logger.LogInformation(Format("The command '{0}' has been updated!", c.Command.Name);
+                }
+
+                updatedCommands++;
+            }
+
+            if (updatedCommands > 0)
+            {
+                OnCommandSetup(workingDict);
+            }
+        }
+
+        void CommandLoaderOnError(object sender, ErrorEventArgs e)
+        {
+            if (!Logger.IsErrorEnabled)
+                return;
+
+            Logger.Error(e.Exception);
+        }
+
+        /// <summary>
+        /// Setups the specified root config.
+        /// </summary>
+        /// <param name="rootConfig">The root config.</param>
+        /// <param name="config">The config.</param>
+        /// <returns></returns>
+        protected virtual bool Setup(IRootConfig rootConfig, IServerConfig config)
+        {
+            return true;
+        }
+
+        partial void SetDefaultCulture(IRootConfig rootConfig, IServerConfig config);
+
+        private void SetupBasic(IRootConfig rootConfig, IServerConfig config, ISocketServerFactory socketServerFactory)
+        {
+            if (rootConfig == null)
+                throw new ArgumentNullException("rootConfig");
+
+            RootConfig = rootConfig;
+
+            if (config == null)
+                throw new ArgumentNullException("config");
+
+            if (!string.IsNullOrEmpty(config.Name))
+                m_Name = config.Name;
+            else
+                m_Name = string.Format("{0}-{1}", this.GetType().Name, Math.Abs(this.GetHashCode()));
+
+            Config = config;
+
+            SetDefaultCulture(rootConfig, config);
+
+            if (!m_ThreadPoolConfigured)
+            {
+                if (!TheadPoolEx.ResetThreadPool(rootConfig.MaxWorkingThreads >= 0 ? rootConfig.MaxWorkingThreads : new Nullable<int>(),
+                        rootConfig.MaxCompletionPortThreads >= 0 ? rootConfig.MaxCompletionPortThreads : new Nullable<int>(),
+                        rootConfig.MinWorkingThreads >= 0 ? rootConfig.MinWorkingThreads : new Nullable<int>(),
+                        rootConfig.MinCompletionPortThreads >= 0 ? rootConfig.MinCompletionPortThreads : new Nullable<int>()))
+                {
+                    throw new Exception("Failed to configure thread pool!");
+                }
+
+                m_ThreadPoolConfigured = true;
+            }
+
+            if (socketServerFactory == null)
+            {
+                var socketServerFactoryType =
+                    Type.GetType("SuperSocket.SocketEngine.SocketServerFactory, SuperSocket.SocketEngine", true);
+
+                socketServerFactory = (ISocketServerFactory)Activator.CreateInstance(socketServerFactoryType);
+            }
+
+            m_SocketServerFactory = socketServerFactory;
+
+            //Read text encoding from the configuration
+            if (!string.IsNullOrEmpty(config.TextEncoding))
+                TextEncoding = Encoding.GetEncoding(config.TextEncoding);
+            else
+                TextEncoding = new ASCIIEncoding();
+        }
+
+        private bool SetupMedium(IReceiveFilterFactory<TRequestInfo> receiveFilterFactory, IEnumerable<IConnectionFilter> connectionFilters, IEnumerable<ICommandLoader<ICommand<TAppSession, TRequestInfo>>> commandLoaders)
+        {
+            if (receiveFilterFactory != null)
+                ReceiveFilterFactory = receiveFilterFactory;
+
+            if (connectionFilters != null && connectionFilters.Any())
+            {
+                if (m_ConnectionFilters == null)
+                    m_ConnectionFilters = new List<IConnectionFilter>();
+
+                m_ConnectionFilters.AddRange(connectionFilters);
+            }
+
+            if (commandLoaders != null && commandLoaders.Any())
+                m_CommandLoaders.AddRange(commandLoaders);
+
+            return SetupCommandLoaders(m_CommandLoaders);
+        }
+
+        private bool SetupAdvanced(IServerConfig config)
+        {
+            if (!SetupSecurity(config))
+                return false;
+
+            if (!SetupListeners(config))
+                return false;
+
+            m_GlobalCommandFilters = GetCommandFilterAttributes(this.GetType());
+
+            var discoveredCommands = new Dictionary<string, ICommand<TAppSession, TRequestInfo>>(StringComparer.OrdinalIgnoreCase);
+            if (!SetupCommands(discoveredCommands))
+                return false;
+
+            OnCommandSetup(discoveredCommands);
+
+            return true;
+        }
+
+        private void OnCommandSetup(IDictionary<string, ICommand<TAppSession, TRequestInfo>> discoveredCommands)
+        {
+            var commandContainer = new Dictionary<string, CommandInfo<ICommand<TAppSession, TRequestInfo>>>(StringComparer.OrdinalIgnoreCase);
+
+            foreach (var command in discoveredCommands.Values)
+            {
+                commandContainer.Add(command.Name,
+                    new CommandInfo<ICommand<TAppSession, TRequestInfo>>(command, m_GlobalCommandFilters));
+            }
+
+            Interlocked.Exchange(ref m_CommandContainer, commandContainer);
+        }
+
+        internal abstract IReceiveFilterFactory<TRequestInfo> CreateDefaultReceiveFilterFactory();
+
+        private bool SetupFinal()
+        {
+            //Check receiveFilterFactory
+            if (ReceiveFilterFactory == null)
+            {
+                ReceiveFilterFactory = CreateDefaultReceiveFilterFactory();
+
+                if (ReceiveFilterFactory == null)
+                {
+                    if (Logger.IsErrorEnabled)
+                        Logger.Error("receiveFilterFactory is required!");
+
+                    return false;
+                }
+            }
+
+            var plainConfig = Config as ServerConfig;
+
+            if (plainConfig == null)
+            {
+                //Using plain config model instead of .NET configuration element to improve performance
+                plainConfig = new ServerConfig(Config);
+
+                if (string.IsNullOrEmpty(plainConfig.Name))
+                    plainConfig.Name = Name;
+
+                Config = plainConfig;
+            }
+
+            try
+            {
+                m_ServerStatus = new StatusInfoCollection();
+                m_ServerStatus.Name = Name;
+                m_ServerStatus.Tag = Name;
+                m_ServerStatus[StatusInfoKeys.MaxConnectionNumber] = Config.MaxConnectionNumber;
+                m_ServerStatus[StatusInfoKeys.Listeners] = m_Listeners;
+            }
+            catch (Exception e)
+            {
+                if (Logger.IsErrorEnabled)
+                    Logger.Error("Failed to create ServerSummary instance!", e);
+
+                return false;
+            }
+
+            return SetupSocketServer();
+        }
+
+        /// <summary>
+        /// Setups with the specified port.
+        /// </summary>
+        /// <param name="port">The port.</param>
+        /// <returns>return setup result</returns>
+        public bool Setup(int port)
+        {
+            return Setup("Any", port);
+        }
+
+        private void TrySetInitializedState()
+        {
+            if (Interlocked.CompareExchange(ref m_StateCode, ServerStateConst.Initializing, ServerStateConst.NotInitialized)
+                    != ServerStateConst.NotInitialized)
+            {
+                throw new Exception("The server has been initialized already, you cannot initialize it again!");
+            }
+        }
+
+#if NET_35
+
+        /// <summary>
+        /// Setups with the specified ip and port.
+        /// </summary>
+        /// <param name="ip">The ip.</param>
+        /// <param name="port">The port.</param>
+        /// <param name="providers">The providers.</param>
+        /// <returns></returns>
+        public bool Setup(string ip, int port, params object[] providers)
+        {
+            return Setup(new ServerConfig
+            {
+                Name = string.Format("{0}-{1}", this.GetType().Name, Math.Abs(this.GetHashCode())),
+                Ip = ip,
+                Port = port
+            }, providers);
+        }
+        /// <summary>
+        /// Setups with the specified config, used for programming setup
+        /// </summary>
+        /// <param name="config">The server config.</param>
+        /// <param name="providers">The providers.</param>
+        /// <returns></returns>
+        public bool Setup(IServerConfig config, params object[] providers)
+        {
+            return Setup(new RootConfig(), config, providers);
+        }
+
+        /// <summary>
+        /// Setups with the specified root config, used for programming setup
+        /// </summary>
+        /// <param name="rootConfig">The root config.</param>
+        /// <param name="config">The server config.</param>
+        /// <param name="providers">The providers.</param>
+        /// <returns></returns>
+        public bool Setup(IRootConfig rootConfig, IServerConfig config, params object[] providers)
+        {
+            TrySetInitializedState();
+
+            SetupBasic(rootConfig, config, GetProviderInstance<ISocketServerFactory>(providers));
+
+            if (!SetupLogFactory(GetProviderInstance<ILogFactory>(providers)))
+                return false;
+
+            Logger = CreateLogger(this.Name);
+
+            if (!SetupMedium(GetProviderInstance<IReceiveFilterFactory<TRequestInfo>>(providers), GetProviderInstance<IEnumerable<IConnectionFilter>>(providers), GetProviderInstance<IEnumerable<ICommandLoader<ICommand<TAppSession, TRequestInfo>>>>(providers)))
+                return false;
+
+            if (!SetupAdvanced(config))
+                return false;
+
+            if (!Setup(rootConfig, config))
+                return false;
+
+            if(!SetupFinal())
+                return false;
+
+            m_StateCode = ServerStateConst.NotStarted;
+            return true;
+        }
+
+        private T GetProviderInstance<T>(object[] providers)
+        {
+            if (providers == null || !providers.Any())
+                return default(T);
+
+            var providerType = typeof(T);
+            return (T)providers.FirstOrDefault(p => p != null && providerType.IsAssignableFrom(p.GetType()));
+        }
+#else
+
+        /// <summary>
+        /// Setups with the specified config.
+        /// </summary>
+        /// <param name="config">The server config.</param>
+        /// <param name="socketServerFactory">The socket server factory.</param>
+        /// <param name="receiveFilterFactory">The receive filter factory.</param>
+        /// <param name="logFactory">The log factory.</param>
+        /// <param name="connectionFilters">The connection filters.</param>
+        /// <param name="commandLoaders">The command loaders.</param>
+        /// <returns></returns>
+        public bool Setup(IServerConfig config, ISocketServerFactory socketServerFactory = null, IReceiveFilterFactory<TRequestInfo> receiveFilterFactory = null, ILogFactory logFactory = null, IEnumerable<IConnectionFilter> connectionFilters = null, IEnumerable<ICommandLoader<ICommand<TAppSession, TRequestInfo>>> commandLoaders = null)
+        {
+            return Setup(new RootConfig(), config, socketServerFactory, receiveFilterFactory, logFactory, connectionFilters, commandLoaders);
+        }
+
+        /// <summary>
+        /// Setups the specified root config, this method used for programming setup
+        /// </summary>
+        /// <param name="rootConfig">The root config.</param>
+        /// <param name="config">The server config.</param>
+        /// <param name="socketServerFactory">The socket server factory.</param>
+        /// <param name="receiveFilterFactory">The Receive filter factory.</param>
+        /// <param name="logFactory">The log factory.</param>
+        /// <param name="connectionFilters">The connection filters.</param>
+        /// <param name="commandLoaders">The command loaders.</param>
+        /// <returns></returns>
+        public bool Setup(IRootConfig rootConfig, IServerConfig config, ISocketServerFactory socketServerFactory = null, IReceiveFilterFactory<TRequestInfo> receiveFilterFactory = null, ILogFactory logFactory = null, IEnumerable<IConnectionFilter> connectionFilters = null, IEnumerable<ICommandLoader<ICommand<TAppSession, TRequestInfo>>> commandLoaders = null)
+        {
+            TrySetInitializedState();
+
+            SetupBasic(rootConfig, config, socketServerFactory);
+
+            if (!SetupLogFactory(logFactory))
+                return false;
+
+            Logger = CreateLogger(this.Name);
+
+            if (!SetupMedium(receiveFilterFactory, connectionFilters, commandLoaders))
+                return false;
+
+            if (!SetupAdvanced(config))
+                return false;
+
+            if (!Setup(rootConfig, config))
+                return false;
+
+            if (!SetupFinal())
+                return false;
+
+            m_StateCode = ServerStateConst.NotStarted;
+            return true;
+        }
+
+        /// <summary>
+        /// Setups with the specified ip and port.
+        /// </summary>
+        /// <param name="ip">The ip.</param>
+        /// <param name="port">The port.</param>
+        /// <param name="socketServerFactory">The socket server factory.</param>
+        /// <param name="receiveFilterFactory">The Receive filter factory.</param>
+        /// <param name="logFactory">The log factory.</param>
+        /// <param name="connectionFilters">The connection filters.</param>
+        /// <param name="commandLoaders">The command loaders.</param>
+        /// <returns>return setup result</returns>
+        public bool Setup(string ip, int port, ISocketServerFactory socketServerFactory = null, IReceiveFilterFactory<TRequestInfo> receiveFilterFactory = null, ILogFactory logFactory = null, IEnumerable<IConnectionFilter> connectionFilters = null, IEnumerable<ICommandLoader<ICommand<TAppSession, TRequestInfo>>> commandLoaders = null)
+        {
+            return Setup(new ServerConfig
+                            {
+                                Ip = ip,
+                                Port = port
+                            },
+                          socketServerFactory,
+                          receiveFilterFactory,
+                          logFactory,
+                          connectionFilters,
+                          commandLoaders);
+        }
+#endif
+
+        /// <summary>
+        /// Setups the specified root config.
+        /// </summary>
+        /// <param name="bootstrap">The bootstrap.</param>
+        /// <param name="config">The socket server instance config.</param>
+        /// <param name="factories">The factories.</param>
+        /// <returns></returns>
+        bool IWorkItem.Setup(IBootstrap bootstrap, IServerConfig config, ProviderFactoryInfo[] factories)
+        {
+            if (bootstrap == null)
+                throw new ArgumentNullException("bootstrap");
+
+            Bootstrap = bootstrap;
+
+            if (factories == null)
+                throw new ArgumentNullException("factories");
+
+            TrySetInitializedState();
+
+            var rootConfig = bootstrap.Config;
+
+            SetupBasic(rootConfig, config, GetSingleProviderInstance<ISocketServerFactory>(factories, ProviderKey.SocketServerFactory));
+
+            if (!SetupLogFactory(GetSingleProviderInstance<ILogFactory>(factories, ProviderKey.LogFactory)))
+                return false;
+
+            Logger = CreateLogger(this.Name);
+
+            IEnumerable<IConnectionFilter> connectionFilters = null;
+
+            if (!TryGetProviderInstances(factories, ProviderKey.ConnectionFilter, null,
+                    (p, f) =>
+                    {
+                        var ret = p.Initialize(f.Name, this);
+
+                        if(!ret)
+                        {
+                            Logger.ErrorFormat("Failed to initialize the connection filter: {0}.", f.Name);
+                        }
+
+                        return ret;
+                    }, out connectionFilters))
+            {
+                return false;
+            }
+
+            if (!SetupMedium(
+                    GetSingleProviderInstance<IReceiveFilterFactory<TRequestInfo>>(factories, ProviderKey.ReceiveFilterFactory),
+                    connectionFilters,
+                    GetProviderInstances<ICommandLoader<ICommand<TAppSession, TRequestInfo>>>(
+                            factories,
+                            ProviderKey.CommandLoader,
+                            (t) => Activator.CreateInstance(t.MakeGenericType(typeof(ICommand<TAppSession, TRequestInfo>))))))
+            {
+                return false;
+            }
+
+            if (!SetupAdvanced(config))
+                return false;
+
+            if (!Setup(rootConfig, config))
+                return false;
+
+            if (!SetupFinal())
+                return false;
+
+            m_StateCode = ServerStateConst.NotStarted;
+            return true;
+        }
+
+
+        private TProvider GetSingleProviderInstance<TProvider>(ProviderFactoryInfo[] factories, ProviderKey key)
+        {
+            var factory = factories.FirstOrDefault(p => p.Key.Name == key.Name);
+
+            if (factory == null)
+                return default(TProvider);
+
+            return factory.ExportFactory.CreateExport<TProvider>();
+        }
+
+        private bool TryGetProviderInstances<TProvider>(ProviderFactoryInfo[] factories, ProviderKey key, Func<Type, object> creator, Func<TProvider, ProviderFactoryInfo, bool> initializer, out IEnumerable<TProvider> providers)
+            where TProvider : class
+        {
+            IEnumerable<ProviderFactoryInfo> selectedFactories = factories.Where(p => p.Key.Name == key.Name);
+
+            if (!selectedFactories.Any())
+            {
+                providers = null;
+                return true;
+            }
+
+            providers = new List<TProvider>();
+
+            var list = (List<TProvider>)providers;
+
+            foreach (var f in selectedFactories)
+            {
+                var provider = creator == null ? f.ExportFactory.CreateExport<TProvider>() : f.ExportFactory.CreateExport<TProvider>(creator);
+
+                if (!initializer(provider, f))
+                    return false;
+
+                list.Add(provider);
+            }
+
+            return true;
+        }
+
+        private IEnumerable<TProvider> GetProviderInstances<TProvider>(ProviderFactoryInfo[] factories, ProviderKey key)
+            where TProvider : class
+        {
+            return GetProviderInstances<TProvider>(factories, key, null);
+        }
+
+        private IEnumerable<TProvider> GetProviderInstances<TProvider>(ProviderFactoryInfo[] factories, ProviderKey key, Func<Type, object> creator)
+            where TProvider : class
+        {
+            IEnumerable<TProvider> providers;
+            TryGetProviderInstances<TProvider>(factories, key, creator, (p, f) => true, out providers);
+            return providers;
+        }
+
+        private bool SetupLogFactory(ILogFactory logFactory)
+        {
+            if (logFactory != null)
+            {
+                LogFactory = logFactory;
+                return true;
+            }
+
+            //Log4NetLogFactory is default log factory
+            if (LogFactory == null)
+                LogFactory = new Log4NetLogFactory();
+
+            return true;
+        }
+
+        /// <summary>
+        /// Setups the command loaders.
+        /// </summary>
+        /// <param name="commandLoaders">The command loaders.</param>
+        /// <returns></returns>
+        protected virtual bool SetupCommandLoaders(List<ICommandLoader<ICommand<TAppSession, TRequestInfo>>> commandLoaders)
+        {
+            commandLoaders.Add(new ReflectCommandLoader<ICommand<TAppSession, TRequestInfo>>());
+            return true;
+        }
+
+        /// <summary>
+        /// Creates the logger for the AppServer.
+        /// </summary>
+        /// <param name="loggerName">Name of the logger.</param>
+        /// <returns></returns>
+        protected virtual ILog CreateLogger(string loggerName)
+        {
+            return LogFactory.GetLog(loggerName);
+        }
+
+        /// <summary>
+        /// Setups the security option of socket communications.
+        /// </summary>
+        /// <param name="config">The config of the server instance.</param>
+        /// <returns></returns>
+        private bool SetupSecurity(IServerConfig config)
+        {
+            if (!string.IsNullOrEmpty(config.Security))
+            {
+                SslProtocols configProtocol;
+                if (!config.Security.TryParseEnum<SslProtocols>(true, out configProtocol))
+                {
+                    if (Logger.IsErrorEnabled)
+                        Logger.ErrorFormat("Failed to parse '{0}' to SslProtocol!", config.Security);
+
+                    return false;
+                }
+
+                BasicSecurity = configProtocol;
+            }
+            else
+            {
+                BasicSecurity = SslProtocols.None;
+            }
+
+            try
+            {
+                var certificate = GetCertificate(config.Certificate);
+
+                if (certificate != null)
+                {
+                    Certificate = certificate;
+                }
+                else if(BasicSecurity != SslProtocols.None)
+                {
+                    if (Logger.IsErrorEnabled)
+                        Logger.Error("Certificate is required in this security mode!");
+
+                    return false;
+                }
+                
+            }
+            catch (Exception e)
+            {
+                if (Logger.IsErrorEnabled)
+                    Logger.Error("Failed to initialize certificate!", e);
+
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Gets the certificate from server configuguration.
+        /// </summary>
+        /// <param name="certificate">The certificate config.</param>
+        /// <returns></returns>
+        protected virtual X509Certificate GetCertificate(ICertificateConfig certificate)
+        {
+            if (certificate == null)
+            {
+                if (BasicSecurity != SslProtocols.None && Logger.IsErrorEnabled)
+                    Logger.Error("There is no certificate configured!");
+                return null;
+            }
+
+            if (string.IsNullOrEmpty(certificate.FilePath) && string.IsNullOrEmpty(certificate.Thumbprint))
+            {
+                if (BasicSecurity != SslProtocols.None && Logger.IsErrorEnabled)
+                    Logger.Error("You should define certificate node and either attribute 'filePath' or 'thumbprint' is required!");
+
+                return null;
+            }
+
+            return CertificateManager.Initialize(certificate, GetFilePath);
+        }
+
+        bool IRemoteCertificateValidator.Validate(IAppSession session, object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
+        {
+            return ValidateClientCertificate((TAppSession)session, sender, certificate, chain, sslPolicyErrors);
+        }
+
+        /// <summary>
+        /// Validates the client certificate. This method is only used if the certificate configuration attribute "clientCertificateRequired" is true.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="sender">The sender.</param>
+        /// <param name="certificate">The certificate.</param>
+        /// <param name="chain">The chain.</param>
+        /// <param name="sslPolicyErrors">The SSL policy errors.</param>
+        /// <returns>return the validation result</returns>
+        protected virtual bool ValidateClientCertificate(TAppSession session, object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
+        {
+            return sslPolicyErrors == SslPolicyErrors.None;
+        }
+
+        /// <summary>
+        /// Setups the socket server.instance
+        /// </summary>
+        /// <returns></returns>
+        private bool SetupSocketServer()
+        {
+            try
+            {
+                m_SocketServer = m_SocketServerFactory.CreateSocketServer<TRequestInfo>(this, m_Listeners, Config);
+                return m_SocketServer != null;
+            }
+            catch (Exception e)
+            {
+                if (Logger.IsErrorEnabled)
+                    Logger.Error(e);
+
+                return false;
+            }
+        }
+
+        private IPAddress ParseIPAddress(string ip)
+        {
+            if (string.IsNullOrEmpty(ip) || "Any".Equals(ip, StringComparison.OrdinalIgnoreCase))
+                return IPAddress.Any;
+            else if ("IPv6Any".Equals(ip, StringComparison.OrdinalIgnoreCase))
+                return IPAddress.IPv6Any;
+            else
+               return IPAddress.Parse(ip);
+        }
+
+        /// <summary>
+        /// Setups the listeners base on server configuration
+        /// </summary>
+        /// <param name="config">The config.</param>
+        /// <returns></returns>
+        private bool SetupListeners(IServerConfig config)
+        {
+            var listeners = new List<ListenerInfo>();
+
+            try
+            {
+                if (config.Port > 0)
+                {
+                    listeners.Add(new ListenerInfo
+                    {
+                        EndPoint = new IPEndPoint(ParseIPAddress(config.Ip), config.Port),
+                        BackLog = config.ListenBacklog,
+                        Security = BasicSecurity
+                    });
+                }
+                else
+                {
+                    //Port is not configured, but ip is configured
+                    if (!string.IsNullOrEmpty(config.Ip))
+                    {
+                        if (Logger.IsErrorEnabled)
+                            Logger.Error("Port is required in config!");
+
+                        return false;
+                    }
+                }
+
+                //There are listener defined
+                if (config.Listeners != null && config.Listeners.Any())
+                {
+                    //But ip and port were configured in server node
+                    //We don't allow this case
+                    if (listeners.Any())
+                    {
+                        if (Logger.IsErrorEnabled)
+                            Logger.Error("If you configured Ip and Port in server node, you cannot defined listener in listeners node any more!");
+
+                        return false;
+                    }
+
+                    foreach (var l in config.Listeners)
+                    {
+                        SslProtocols configProtocol;
+
+                        if (string.IsNullOrEmpty(l.Security))
+                        {
+                            configProtocol = BasicSecurity;
+                        }
+                        else if (!l.Security.TryParseEnum<SslProtocols>(true, out configProtocol))
+                        {
+                            if (Logger.IsErrorEnabled)
+                                Logger.ErrorFormat("Failed to parse '{0}' to SslProtocol!", config.Security);
+
+                            return false;
+                        }
+
+                        if (configProtocol != SslProtocols.None && (Certificate == null))
+                        {
+                            if (Logger.IsErrorEnabled)
+                                Logger.Error("There is no certificate loaded, but there is a secure listener defined!");
+                            return false;
+                        }
+
+                        listeners.Add(new ListenerInfo
+                        {
+                            EndPoint = new IPEndPoint(ParseIPAddress(l.Ip), l.Port),
+                            BackLog = l.Backlog,
+                            Security = configProtocol
+                        });
+                    }
+                }
+
+                if (!listeners.Any())
+                {
+                    if (Logger.IsErrorEnabled)
+                        Logger.Error("No listener defined!");
+
+                    return false;
+                }
+
+                m_Listeners = listeners.ToArray();
+
+                return true;
+            }
+            catch (Exception e)
+            {
+                if (Logger.IsErrorEnabled)
+                    Logger.Error(e);
+
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets the name of the server instance.
+        /// </summary>
+        public string Name
+        {
+            get { return m_Name; }
+        }
+
+        private ISocketServer m_SocketServer;
+
+        /// <summary>
+        /// Gets the socket server.
+        /// </summary>
+        /// <value>
+        /// The socket server.
+        /// </value>
+        ISocketServer ISocketServerAccessor.SocketServer
+        {
+            get { return m_SocketServer; }
+        }
+
+        /// <summary>
+        /// Starts this server instance.
+        /// </summary>
+        /// <returns>
+        /// return true if start successfull, else false
+        /// </returns>
+        public virtual bool Start()
+        {
+            var origStateCode = Interlocked.CompareExchange(ref m_StateCode, ServerStateConst.Starting, ServerStateConst.NotStarted);
+
+            if (origStateCode != ServerStateConst.NotStarted)
+            {
+                if (origStateCode < ServerStateConst.NotStarted)
+                    throw new Exception("You cannot start a server instance which has not been setup yet.");
+
+                if (Logger.IsErrorEnabled)
+                    Logger.ErrorFormat("This server instance is in the state {0}, you cannot start it now.", (ServerState)origStateCode);
+
+                return false;
+            }
+
+            if (!m_SocketServer.Start())
+            {
+                m_StateCode = ServerStateConst.NotStarted;
+                return false;
+            }
+
+            StartedTime = DateTime.Now;
+            m_StateCode = ServerStateConst.Running;
+
+            m_ServerStatus[StatusInfoKeys.IsRunning] = true;
+            m_ServerStatus[StatusInfoKeys.StartedTime] = StartedTime;
+
+            try
+            {
+                //Will be removed in the next version
+#pragma warning disable 0612, 618
+                OnStartup();
+#pragma warning restore 0612, 618
+
+                OnStarted();
+            }
+            catch (Exception e)
+            {
+                if (Logger.IsErrorEnabled)
+                {
+                    Logger.Error("One exception wa thrown in the method 'OnStartup()'.", e);
+                }
+            }
+            finally
+            {
+                if (Logger.IsInfoEnabled)
+                    logger.LogInformation(string.Format("The server instance {0} has been started!", Name));
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Called when [startup].
+        /// </summary>
+        [Obsolete("Use OnStarted() instead")]
+        protected virtual void OnStartup()
+        {
+
+        }
+
+        /// <summary>
+        /// Called when [started].
+        /// </summary>
+        protected virtual void OnStarted()
+        {
+
+        }
+
+        /// <summary>
+        /// Called when [stopped].
+        /// </summary>
+        protected virtual void OnStopped()
+        {
+
+        }
+
+        /// <summary>
+        /// Stops this server instance.
+        /// </summary>
+        public virtual void Stop()
+        {
+            if (Interlocked.CompareExchange(ref m_StateCode, ServerStateConst.Stopping, ServerStateConst.Running)
+                    != ServerStateConst.Running)
+            {
+                return;
+            }
+
+            m_SocketServer.Stop();
+
+            m_StateCode = ServerStateConst.NotStarted;
+
+            OnStopped();
+
+            m_ServerStatus[StatusInfoKeys.IsRunning] = false;
+            m_ServerStatus[StatusInfoKeys.StartedTime] = null;
+
+            if (Logger.IsInfoEnabled)
+                logger.LogInformation(string.Format("The server instance {0} has been stopped!", Name));
+        }
+
+        /// <summary>
+        /// Gets command by command name.
+        /// </summary>
+        /// <param name="commandName">Name of the command.</param>
+        /// <returns></returns>
+        private CommandInfo<ICommand<TAppSession, TRequestInfo>> GetCommandByName(string commandName)
+        {
+            CommandInfo<ICommand<TAppSession, TRequestInfo>> commandProxy;
+
+            if (m_CommandContainer.TryGetValue(commandName, out commandProxy))
+                return commandProxy;
+            else
+                return null;
+        }
+
+
+        private Func<TAppSession, byte[], int, int, bool> m_RawDataReceivedHandler;
+
+        /// <summary>
+        /// Gets or sets the raw binary data received event handler.
+        /// TAppSession: session
+        /// byte[]: receive buffer
+        /// int: receive buffer offset
+        /// int: receive lenght
+        /// bool: whether process the received data further
+        /// </summary>
+        event Func<TAppSession, byte[], int, int, bool> IRawDataProcessor<TAppSession>.RawDataReceived
+        {
+            add { m_RawDataReceivedHandler += value; }
+            remove { m_RawDataReceivedHandler -= value; }
+        }
+
+        /// <summary>
+        /// Called when [raw data received].
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="buffer">The buffer.</param>
+        /// <param name="offset">The offset.</param>
+        /// <param name="length">The length.</param>
+        internal bool OnRawDataReceived(IAppSession session, byte[] buffer, int offset, int length)
+        {
+            var handler = m_RawDataReceivedHandler;
+            if (handler == null)
+                return true;
+
+            return handler((TAppSession)session, buffer, offset, length);
+        }
+
+        private RequestHandler<TAppSession, TRequestInfo> m_RequestHandler;
+
+        /// <summary>
+        /// Occurs when a full request item received.
+        /// </summary>
+        public virtual event RequestHandler<TAppSession, TRequestInfo> NewRequestReceived
+        {
+            add { m_RequestHandler += value; }
+            remove { m_RequestHandler -= value; }
+        }
+
+        /// <summary>
+        /// Executes the command.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="requestInfo">The request info.</param>
+        protected virtual void ExecuteCommand(TAppSession session, TRequestInfo requestInfo)
+        {
+            if (m_RequestHandler == null)
+            {
+                var commandProxy = GetCommandByName(requestInfo.Key);
+
+                if (commandProxy != null)
+                {
+                    var command = commandProxy.Command;
+                    var commandFilters = commandProxy.Filters;
+
+                    session.CurrentCommand = requestInfo.Key;
+
+                    var cancelled = false;
+
+                    if (commandFilters == null)
+                    {
+                        command.ExecuteCommand(session, requestInfo);
+                    }
+                    else
+                    {
+                        var commandContext = new CommandExecutingContext();
+                        commandContext.Initialize(session, requestInfo, command);
+
+                        for (var i = 0; i < commandFilters.Length; i++)
+                        {
+                            var filter = commandFilters[i];
+                            filter.OnCommandExecuting(commandContext);
+
+                            if (commandContext.Cancel)
+                            {
+                                cancelled = true;
+                                if(Logger.IsInfoEnabled)
+                                    logger.LogInformation(session, string.Format("The executing of the command {0} was cancelled by the command filter {1}.", command.Name, filter.GetType().ToString()));
+                                break;
+                            }
+                        }
+
+                        if (!cancelled)
+                        {
+                            try
+                            {
+                                command.ExecuteCommand(session, requestInfo);
+                            }
+                            catch (Exception exc)
+                            {
+                                commandContext.Exception = exc;
+                            }
+
+                            for (var i = 0; i < commandFilters.Length; i++)
+                            {
+                                var filter = commandFilters[i];
+                                filter.OnCommandExecuted(commandContext);
+                            }
+
+                            if (commandContext.Exception != null && !commandContext.ExceptionHandled)
+                            {
+                                try
+                                {
+                                    session.InternalHandleExcetion(commandContext.Exception);
+                                }
+                                catch
+                                {
+
+                                }
+                            }
+                        }
+                    }
+
+                    if(!cancelled)
+                    {
+                        session.PrevCommand = requestInfo.Key;
+
+                        if (Config.LogCommand && Logger.IsInfoEnabled)
+                            logger.LogInformation(session, string.Format("Command - {0}", requestInfo.Key));
+                    }
+                }
+                else
+                {
+                    session.InternalHandleUnknownRequest(requestInfo);
+                }
+
+                session.LastActiveTime = DateTime.Now;
+            }
+            else
+            {
+                session.CurrentCommand = requestInfo.Key;
+
+                try
+                {
+                    m_RequestHandler(session, requestInfo);
+                }
+                catch (Exception e)
+                {
+                    session.InternalHandleExcetion(e);
+                }
+                
+                session.PrevCommand = requestInfo.Key;
+                session.LastActiveTime = DateTime.Now;
+
+                if (Config.LogCommand && Logger.IsInfoEnabled)
+                    logger.LogInformation(session, string.Format("Command - {0}", requestInfo.Key));
+            }
+
+            Interlocked.Increment(ref m_TotalHandledRequests);
+        }
+
+        /// <summary>
+        /// Executes the command for the session.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="requestInfo">The request info.</param>
+        internal void ExecuteCommand(IAppSession session, TRequestInfo requestInfo)
+        {
+            this.ExecuteCommand((TAppSession)session, requestInfo);
+        }
+
+        /// <summary>
+        /// Executes the command.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="requestInfo">The request info.</param>
+        void IRequestHandler<TRequestInfo>.ExecuteCommand(IAppSession session, TRequestInfo requestInfo)
+        {
+            this.ExecuteCommand((TAppSession)session, requestInfo);
+        }
+
+        /// <summary>
+        /// Gets or sets the server's connection filter
+        /// </summary>
+        /// <value>
+        /// The server's connection filters
+        /// </value>
+        public IEnumerable<IConnectionFilter> ConnectionFilters
+        {
+            get { return m_ConnectionFilters; }
+        }
+
+        /// <summary>
+        /// Executes the connection filters.
+        /// </summary>
+        /// <param name="remoteAddress">The remote address.</param>
+        /// <returns></returns>
+        private bool ExecuteConnectionFilters(IPEndPoint remoteAddress)
+        {
+            if (m_ConnectionFilters == null)
+                return true;
+
+            for (var i = 0; i < m_ConnectionFilters.Count; i++)
+            {
+                var currentFilter = m_ConnectionFilters[i];
+                if (!currentFilter.AllowConnect(remoteAddress))
+                {
+                    if (Logger.IsInfoEnabled)
+                        logger.LogInformation(Format("A connection from {0} has been refused by filter {1}!", remoteAddress, currentFilter.Name);
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Creates the app session.
+        /// </summary>
+        /// <param name="socketSession">The socket session.</param>
+        /// <returns></returns>
+        IAppSession IAppServer.CreateAppSession(ISocketSession socketSession)
+        {
+            if (!ExecuteConnectionFilters(socketSession.RemoteEndPoint))
+                return NullAppSession;
+
+            var appSession = CreateAppSession(socketSession);
+            
+            appSession.Initialize(this, socketSession);
+
+            return appSession;
+        }
+
+        /// <summary>
+        /// create a new TAppSession instance, you can override it to create the session instance in your own way
+        /// </summary>
+        /// <param name="socketSession">the socket session.</param>
+        /// <returns>the new created session instance</returns>
+        protected virtual TAppSession CreateAppSession(ISocketSession socketSession)
+        {
+            return new TAppSession();
+        }
+
+        /// <summary>
+        /// Registers the new created app session into the appserver's session container.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <returns></returns>
+        bool IAppServer.RegisterSession(IAppSession session)
+        {
+            var appSession = session as TAppSession;
+
+            if (!RegisterSession(appSession.SessionID, appSession))
+                return false;
+
+            appSession.SocketSession.Closed += OnSocketSessionClosed;
+
+            if (Config.LogBasicSessionActivity && Logger.IsInfoEnabled)
+                logger.LogInformation(session, "A new session connected! ");
+
+            OnNewSessionConnected(appSession);
+            return true;
+        }
+
+        /// <summary>
+        /// Registers the session into session container.
+        /// </summary>
+        /// <param name="sessionID">The session ID.</param>
+        /// <param name="appSession">The app session.</param>
+        /// <returns></returns>
+        protected virtual bool RegisterSession(string sessionID, TAppSession appSession)
+        {
+            return true;
+        }
+
+
+        private SessionHandler<TAppSession> m_NewSessionConnected;
+
+        /// <summary>
+        /// The action which will be executed after a new session connect
+        /// </summary>
+        public event SessionHandler<TAppSession> NewSessionConnected
+        {
+            add { m_NewSessionConnected += value; }
+            remove { m_NewSessionConnected -= value; }
+        }
+
+        /// <summary>
+        /// Called when [new session connected].
+        /// </summary>
+        /// <param name="session">The session.</param>
+        protected virtual void OnNewSessionConnected(TAppSession session)
+        {
+            var handler = m_NewSessionConnected;
+            if (handler == null)
+                return;
+
+            handler.BeginInvoke(session, OnNewSessionConnectedCallback, handler);
+        }
+
+        private void OnNewSessionConnectedCallback(IAsyncResult result)
+        {
+            try
+            {
+                var handler = (SessionHandler<TAppSession>)result.AsyncState;
+                handler.EndInvoke(result);
+            }
+            catch (Exception e)
+            {
+                Logger.Error(e);
+            }
+        }
+
+        /// <summary>
+        /// Resets the session's security protocol.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="security">The security protocol.</param>
+        public void ResetSessionSecurity(IAppSession session, SslProtocols security)
+        {
+            m_SocketServer.ResetSessionSecurity(session, security);
+        }
+
+        /// <summary>
+        /// Called when [socket session closed].
+        /// </summary>
+        /// <param name="session">The socket session.</param>
+        /// <param name="reason">The reason.</param>
+        private void OnSocketSessionClosed(ISocketSession session, CloseReason reason)
+        {
+            //Even if LogBasicSessionActivity is false, we also log the unexpected closing because the close reason probably be useful
+            if (Logger.IsInfoEnabled && (Config.LogBasicSessionActivity || (reason != CloseReason.ServerClosing && reason != CloseReason.ClientClosing && reason != CloseReason.ServerShutdown && reason != CloseReason.SocketError)))
+                logger.LogInformation(session, string.Format("This session was closed for {0}!", reason));
+
+            var appSession = session.AppSession as TAppSession;
+            appSession.Connected = false;
+            OnSessionClosed(appSession, reason);
+        }
+
+        private SessionHandler<TAppSession, CloseReason> m_SessionClosed;
+        /// <summary>
+        /// Gets/sets the session closed event handler.
+        /// </summary>
+        public event SessionHandler<TAppSession, CloseReason> SessionClosed
+        {
+            add { m_SessionClosed += value; }
+            remove { m_SessionClosed -= value; }
+        }
+
+        /// <summary>
+        /// Called when [session closed].
+        /// </summary>
+        /// <param name="session">The appSession.</param>
+        /// <param name="reason">The reason.</param>
+        protected virtual void OnSessionClosed(TAppSession session, CloseReason reason)
+        {
+            var handler = m_SessionClosed;
+
+            if (handler != null)
+            {
+                handler.BeginInvoke(session, reason, OnSessionClosedCallback, handler);
+            }
+
+            session.OnSessionClosed(reason);
+        }
+
+        private void OnSessionClosedCallback(IAsyncResult result)
+        {
+            try
+            {
+                var handler = (SessionHandler<TAppSession, CloseReason>)result.AsyncState;
+                handler.EndInvoke(result);
+            }
+            catch (Exception e)
+            {
+                Logger.Error(e);
+            }
+        }
+
+        /// <summary>
+        /// Gets the app session by ID.
+        /// </summary>
+        /// <param name="sessionID">The session ID.</param>
+        /// <returns></returns>
+        public abstract TAppSession GetSessionByID(string sessionID);
+
+        /// <summary>
+        /// Gets the app session by ID.
+        /// </summary>
+        /// <param name="sessionID"></param>
+        /// <returns></returns>
+        IAppSession IAppServer.GetSessionByID(string sessionID)
+        {
+            return this.GetSessionByID(sessionID);
+        }
+
+        /// <summary>
+        /// Gets the matched sessions from sessions snapshot.
+        /// </summary>
+        /// <param name="critera">The prediction critera.</param>
+        public virtual IEnumerable<TAppSession> GetSessions(Func<TAppSession, bool> critera)
+        {
+            throw new NotSupportedException();
+        }
+
+        /// <summary>
+        /// Gets all sessions in sessions snapshot.
+        /// </summary>
+        public virtual IEnumerable<TAppSession> GetAllSessions()
+        {
+            throw new NotSupportedException();
+        }
+
+        /// <summary>
+        /// Gets the total session count.
+        /// </summary>
+        public abstract int SessionCount { get; }
+
+        /// <summary>
+        /// Gets the physical file path by the relative file path,
+        /// search both in the appserver's root and in the supersocket root dir if the isolation level has been set other than 'None'.
+        /// </summary>
+        /// <param name="relativeFilePath">The relative file path.</param>
+        /// <returns></returns>
+        public string GetFilePath(string relativeFilePath)
+        {
+            var filePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, relativeFilePath);
+
+            if (!System.IO.File.Exists(filePath) && RootConfig != null && RootConfig.Isolation != IsolationMode.None)
+            {
+                var rootDir = System.IO.Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.FullName;
+                var rootFilePath = System.IO.Path.Combine(rootDir, relativeFilePath);
+
+                if (System.IO.File.Exists(rootFilePath))
+                    return rootFilePath;
+            }
+
+            return filePath;
+        }
+
+        #region IActiveConnector
+
+        /// <summary>
+        /// Connect the remote endpoint actively.
+        /// </summary>
+        /// <param name="targetEndPoint">The target end point.</param>
+        /// <param name="localEndPoint">The local end point.</param>
+        /// <returns></returns>
+        /// <exception cref="System.Exception">This server cannot support active connect.</exception>
+        Task<ActiveConnectResult> IActiveConnector.ActiveConnect(EndPoint targetEndPoint, EndPoint localEndPoint)
+        {
+            var activeConnector = m_SocketServer as IActiveConnector;
+
+            if (activeConnector == null)
+                throw new Exception("This server cannot support active connect.");
+
+            return activeConnector.ActiveConnect(targetEndPoint, localEndPoint);
+        }
+
+        /// <summary>
+        /// Connect the remote endpoint actively.
+        /// </summary>
+        /// <param name="targetEndPoint">The target end point.</param>
+        /// <returns></returns>
+        /// <exception cref="System.Exception">This server cannot support active connect.</exception>
+        Task<ActiveConnectResult> IActiveConnector.ActiveConnect(EndPoint targetEndPoint)
+        {
+            return ((IActiveConnector)this).ActiveConnect(targetEndPoint, null);
+        }
+
+        #endregion IActiveConnector
+
+        #region ISystemEndPoint
+        /// <summary>
+        /// Transfers the system message
+        /// </summary>
+        /// <param name="messageType">Type of the message.</param>
+        /// <param name="messageData">The message data.</param>
+        void ISystemEndPoint.TransferSystemMessage(string messageType, object messageData)
+        {
+            OnSystemMessageReceived(messageType, messageData);
+        }
+
+        /// <summary>
+        /// Called when [system message received].
+        /// </summary>
+        /// <param name="messageType">Type of the message.</param>
+        /// <param name="messageData">The message data.</param>
+        protected virtual void OnSystemMessageReceived(string messageType, object messageData)
+        {
+
+        }
+
+        #endregion ISystemEndPoint
+
+        #region IStatusInfoSource
+
+        private StatusInfoCollection m_ServerStatus;
+
+        StatusInfoAttribute[] IStatusInfoSource.GetServerStatusMetadata()
+        {
+            return this.GetType().GetStatusInfoMetadata();
+        }
+
+        StatusInfoCollection IStatusInfoSource.CollectServerStatus(StatusInfoCollection bootstrapStatus)
+        {
+            UpdateServerStatus(m_ServerStatus);
+            this.AsyncRun(() => OnServerStatusCollected(bootstrapStatus, m_ServerStatus), e => Logger.Error(e));
+            return m_ServerStatus;
+        }
+
+        /// <summary>
+        /// Updates the summary of the server.
+        /// </summary>
+        /// <param name="serverStatus">The server status.</param>
+        protected virtual void UpdateServerStatus(StatusInfoCollection serverStatus)
+        {
+            DateTime now = DateTime.Now;
+
+            serverStatus[StatusInfoKeys.IsRunning] = m_StateCode == ServerStateConst.Running;
+            serverStatus[StatusInfoKeys.TotalConnections] = this.SessionCount;
+
+            var totalHandledRequests0 = serverStatus.GetValue<long>(StatusInfoKeys.TotalHandledRequests, 0);
+
+            var totalHandledRequests = this.TotalHandledRequests;
+
+            serverStatus[StatusInfoKeys.RequestHandlingSpeed] = ((totalHandledRequests - totalHandledRequests0) / now.Subtract(serverStatus.CollectedTime).TotalSeconds);
+            serverStatus[StatusInfoKeys.TotalHandledRequests] = totalHandledRequests;
+
+            if (State == ServerState.Running)
+            {
+                var sendingQueuePool = m_SocketServer.SendingQueuePool;
+                serverStatus[StatusInfoKeys.AvialableSendingQueueItems] = sendingQueuePool.AvialableItemsCount;
+                serverStatus[StatusInfoKeys.TotalSendingQueueItems] = sendingQueuePool.TotalItemsCount;
+            }
+            else
+            {
+                serverStatus[StatusInfoKeys.AvialableSendingQueueItems] = 0;
+                serverStatus[StatusInfoKeys.TotalSendingQueueItems] = 0;
+            }
+
+            serverStatus.CollectedTime = now;
+        }
+
+        /// <summary>
+        /// Called when [server status collected].
+        /// </summary>
+        /// <param name="bootstrapStatus">The bootstrapStatus status.</param>
+        /// <param name="serverStatus">The server status.</param>
+        protected virtual void OnServerStatusCollected(StatusInfoCollection bootstrapStatus, StatusInfoCollection serverStatus)
+        {
+
+        }
+
+        #endregion IStatusInfoSource
+
+        #region IDisposable Members
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources
+        /// </summary>
+        public void Dispose()
+        {
+            if (m_StateCode == ServerStateConst.Running)
+                Stop();
+        }
+
+        #endregion
+    }
+}

+ 689 - 0
SocketBase.backup/AppSession.cs

@@ -0,0 +1,689 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Security.Authentication;
+using System.Text;
+using System.Threading;
+using SuperSocket.Common;
+using SuperSocket.SocketBase.Command;
+using SuperSocket.SocketBase.Config;
+using SuperSocket.SocketBase.Logging;
+using SuperSocket.SocketBase.Protocol;
+
+namespace SuperSocket.SocketBase
+{
+    /// <summary>
+    /// AppSession base class
+    /// </summary>
+    /// <typeparam name="TAppSession">The type of the app session.</typeparam>
+    /// <typeparam name="TRequestInfo">The type of the request info.</typeparam>
+    public abstract class AppSession<TAppSession, TRequestInfo> : IAppSession, IAppSession<TAppSession, TRequestInfo>
+        where TAppSession : AppSession<TAppSession, TRequestInfo>, IAppSession, new()
+        where TRequestInfo : class, IRequestInfo
+    {
+        #region Properties
+
+        /// <summary>
+        /// Gets the app server instance assosiated with the session.
+        /// </summary>
+        public virtual AppServerBase<TAppSession, TRequestInfo> AppServer { get; private set; }
+
+        /// <summary>
+        /// Gets the app server instance assosiated with the session.
+        /// </summary>
+        IAppServer IAppSession.AppServer
+        {
+            get { return this.AppServer; }
+        }
+
+        /// <summary>
+        /// Gets or sets the charset which is used for transfering text message.
+        /// </summary>
+        /// <value>
+        /// The charset.
+        /// </value>
+        public Encoding Charset { get; set; }
+
+        private IDictionary<object, object> m_Items;
+
+        /// <summary>
+        /// Gets the items dictionary, only support 10 items maximum
+        /// </summary>
+        public IDictionary<object, object> Items
+        {
+            get
+            {
+                if (m_Items == null)
+                    m_Items = new Dictionary<object, object>(10);
+
+                return m_Items;
+            }
+        }
+
+
+        private bool m_Connected = false;
+
+        /// <summary>
+        /// Gets a value indicating whether this <see cref="IAppSession"/> is connected.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if connected; otherwise, <c>false</c>.
+        /// </value>
+        public bool Connected
+        {
+            get { return m_Connected; }
+            internal set { m_Connected = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the previous command.
+        /// </summary>
+        /// <value>
+        /// The prev command.
+        /// </value>
+        public string PrevCommand { get; set; }
+
+        /// <summary>
+        /// Gets or sets the current executing command.
+        /// </summary>
+        /// <value>
+        /// The current command.
+        /// </value>
+        public string CurrentCommand { get; set; }
+
+
+        /// <summary>
+        /// Gets or sets the secure protocol of transportation layer.
+        /// </summary>
+        /// <value>
+        /// The secure protocol.
+        /// </value>
+        public SslProtocols SecureProtocol
+        {
+            get { return SocketSession.SecureProtocol; }
+            set { SocketSession.SecureProtocol = value; }
+        }
+
+        /// <summary>
+        /// Gets the local listening endpoint.
+        /// </summary>
+        public IPEndPoint LocalEndPoint
+        {
+            get { return SocketSession.LocalEndPoint; }
+        }
+
+        /// <summary>
+        /// Gets the remote endpoint of client.
+        /// </summary>
+        public IPEndPoint RemoteEndPoint
+        {
+            get { return SocketSession.RemoteEndPoint; }
+        }
+
+        /// <summary>
+        /// Gets the logger.
+        /// </summary>
+        public ILog Logger
+        {
+            get { return AppServer.Logger; }
+        }
+
+        /// <summary>
+        /// Gets or sets the last active time of the session.
+        /// </summary>
+        /// <value>
+        /// The last active time.
+        /// </value>
+        public DateTime LastActiveTime { get; set; }
+
+        /// <summary>
+        /// Gets the start time of the session.
+        /// </summary>
+        public DateTime StartTime { get; private set; }
+
+        /// <summary>
+        /// Gets the session ID.
+        /// </summary>
+        public string SessionID { get; private set; }
+
+        /// <summary>
+        /// Gets the socket session of the AppSession.
+        /// </summary>
+        public ISocketSession SocketSession { get; private set; }
+
+        /// <summary>
+        /// Gets the config of the server.
+        /// </summary>
+        public IServerConfig Config
+        {
+            get { return AppServer.Config; }
+        }
+
+        IReceiveFilter<TRequestInfo> m_ReceiveFilter;
+
+        #endregion
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppSession&lt;TAppSession, TRequestInfo&gt;"/> class.
+        /// </summary>
+        public AppSession()
+        {
+            this.StartTime = DateTime.Now;
+            this.LastActiveTime = this.StartTime;
+        }
+
+
+        /// <summary>
+        /// Initializes the specified app session by AppServer and SocketSession.
+        /// </summary>
+        /// <param name="appServer">The app server.</param>
+        /// <param name="socketSession">The socket session.</param>
+        public virtual void Initialize(IAppServer<TAppSession, TRequestInfo> appServer, ISocketSession socketSession)
+        {
+            var castedAppServer = (AppServerBase<TAppSession, TRequestInfo>)appServer;
+            AppServer = castedAppServer;
+            Charset = castedAppServer.TextEncoding;
+            SocketSession = socketSession;
+            SessionID = socketSession.SessionID;
+            m_Connected = true;
+            m_ReceiveFilter = castedAppServer.ReceiveFilterFactory.CreateFilter(appServer, this, socketSession.RemoteEndPoint);
+
+            var filterInitializer = m_ReceiveFilter as IReceiveFilterInitializer;
+            if (filterInitializer != null)
+                filterInitializer.Initialize(castedAppServer, this);
+
+            socketSession.Initialize(this);
+
+            OnInit();
+        }
+
+        /// <summary>
+        /// Starts the session.
+        /// </summary>
+        void IAppSession.StartSession()
+        {
+            OnSessionStarted();
+        }
+
+        /// <summary>
+        /// Called when [init].
+        /// </summary>
+        protected virtual void OnInit()
+        {
+            
+        }
+
+        /// <summary>
+        /// Called when [session started].
+        /// </summary>
+        protected virtual void OnSessionStarted()
+        {
+
+        }
+
+        /// <summary>
+        /// Called when [session closed].
+        /// </summary>
+        /// <param name="reason">The reason.</param>
+        internal protected virtual void OnSessionClosed(CloseReason reason)
+        {
+
+        }
+
+
+        /// <summary>
+        /// Handles the exceptional error, it only handles application error.
+        /// </summary>
+        /// <param name="e">The exception.</param>
+        protected virtual void HandleException(Exception e)
+        {
+            Logger.Error(this, e);
+            this.Close(CloseReason.ApplicationError);
+        }
+
+        /// <summary>
+        /// Handles the unknown request.
+        /// </summary>
+        /// <param name="requestInfo">The request info.</param>
+        protected virtual void HandleUnknownRequest(TRequestInfo requestInfo)
+        {
+
+        }
+
+        internal void InternalHandleUnknownRequest(TRequestInfo requestInfo)
+        {
+            HandleUnknownRequest(requestInfo);
+        }
+
+        internal void InternalHandleExcetion(Exception e)
+        {
+            HandleException(e);
+        }
+
+        /// <summary>
+        /// Closes the session by the specified reason.
+        /// </summary>
+        /// <param name="reason">The close reason.</param>
+        public virtual void Close(CloseReason reason)
+        {
+            this.SocketSession.Close(reason);
+        }
+
+        /// <summary>
+        /// Closes this session.
+        /// </summary>
+        public virtual void Close()
+        {
+            Close(CloseReason.ServerClosing);
+        }
+
+        #region Sending processing
+
+        /// <summary>
+        /// Try to send the message to client.
+        /// </summary>
+        /// <param name="message">The message which will be sent.</param>
+        /// <returns>Indicate whether the message was pushed into the sending queue</returns>
+        public virtual bool TrySend(string message)
+        {
+            var data = this.Charset.GetBytes(message);
+            return InternalTrySend(new ArraySegment<byte>(data, 0, data.Length));
+        }
+
+        /// <summary>
+        /// Sends the message to client.
+        /// </summary>
+        /// <param name="message">The message which will be sent.</param>
+        public virtual void Send(string message)
+        {
+            var data = this.Charset.GetBytes(message);
+            Send(data, 0, data.Length);
+        }
+
+        /// <summary>
+        /// Try to send the data to client.
+        /// </summary>
+        /// <param name="data">The data which will be sent.</param>
+        /// <param name="offset">The offset.</param>
+        /// <param name="length">The length.</param>
+        /// <returns>Indicate whether the message was pushed into the sending queue</returns>
+        public virtual bool TrySend(byte[] data, int offset, int length)
+        {
+            return InternalTrySend(new ArraySegment<byte>(data, offset, length));
+        }
+
+        /// <summary>
+        /// Sends the data to client.
+        /// </summary>
+        /// <param name="data">The data which will be sent.</param>
+        /// <param name="offset">The offset.</param>
+        /// <param name="length">The length.</param>
+        public virtual void Send(byte[] data, int offset, int length)
+        {
+            InternalSend(new ArraySegment<byte>(data, offset, length));
+        }
+
+        private bool InternalTrySend(ArraySegment<byte> segment)
+        {
+            if (!SocketSession.TrySend(segment))
+                return false;
+
+            LastActiveTime = DateTime.Now;
+            return true;
+        }
+
+        /// <summary>
+        /// Try to send the data segment to client.
+        /// </summary>
+        /// <param name="segment">The segment which will be sent.</param>
+        /// <returns>Indicate whether the message was pushed into the sending queue</returns>
+        public virtual bool TrySend(ArraySegment<byte> segment)
+        {
+            if (!m_Connected)
+                return false;
+
+            return InternalTrySend(segment);
+        }
+
+
+        private void InternalSend(ArraySegment<byte> segment)
+        {
+            if (!m_Connected)
+                return;
+
+            if (InternalTrySend(segment))
+                return;
+
+            var sendTimeOut = Config.SendTimeOut;
+
+            //Don't retry, timeout directly
+            if (sendTimeOut < 0)
+            {
+                throw new TimeoutException("The sending attempt timed out");
+            }
+
+            var timeOutTime = sendTimeOut > 0 ? DateTime.Now.AddMilliseconds(sendTimeOut) : DateTime.Now;
+
+            var spinWait = new SpinWait();
+
+            while (m_Connected)
+            {
+                spinWait.SpinOnce();
+
+                if (InternalTrySend(segment))
+                    return;
+
+                //If sendTimeOut = 0, don't have timeout check
+                if (sendTimeOut > 0 && DateTime.Now >= timeOutTime)
+                {
+                    throw new TimeoutException("The sending attempt timed out");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Sends the data segment to client.
+        /// </summary>
+        /// <param name="segment">The segment which will be sent.</param>
+        public virtual void Send(ArraySegment<byte> segment)
+        {
+            InternalSend(segment);
+        }
+
+        private bool InternalTrySend(IList<ArraySegment<byte>> segments)
+        {
+            if (!SocketSession.TrySend(segments))
+                return false;
+
+            LastActiveTime = DateTime.Now;
+            return true;
+        }
+
+        /// <summary>
+        /// Try to send the data segments to client.
+        /// </summary>
+        /// <param name="segments">The segments.</param>
+        /// <returns>Indicate whether the message was pushed into the sending queue; if it returns false, the sending queue may be full or the socket is not connected</returns>
+        public virtual bool TrySend(IList<ArraySegment<byte>> segments)
+        {
+            if (!m_Connected)
+                return false;
+
+            return InternalTrySend(segments);
+        }
+
+        private void InternalSend(IList<ArraySegment<byte>> segments)
+        {
+            if (!m_Connected)
+                return;
+
+            if (InternalTrySend(segments))
+                return;
+
+            var sendTimeOut = Config.SendTimeOut;
+
+            //Don't retry, timeout directly
+            if (sendTimeOut < 0)
+            {
+                throw new TimeoutException("The sending attempt timed out");
+            }
+
+            var timeOutTime = sendTimeOut > 0 ? DateTime.Now.AddMilliseconds(sendTimeOut) : DateTime.Now;
+
+            var spinWait = new SpinWait();
+
+            while (m_Connected)
+            {
+                spinWait.SpinOnce();
+
+                if (InternalTrySend(segments))
+                    return;
+
+                //If sendTimeOut = 0, don't have timeout check
+                if (sendTimeOut > 0 && DateTime.Now >= timeOutTime)
+                {
+                    throw new TimeoutException("The sending attempt timed out");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Sends the data segments to client.
+        /// </summary>
+        /// <param name="segments">The segments.</param>
+        public virtual void Send(IList<ArraySegment<byte>> segments)
+        {
+            InternalSend(segments);
+        }
+
+        /// <summary>
+        /// Sends the response.
+        /// </summary>
+        /// <param name="message">The message which will be sent.</param>
+        /// <param name="paramValues">The parameter values.</param>
+        public virtual void Send(string message, params object[] paramValues)
+        {
+            var data = this.Charset.GetBytes(string.Format(message, paramValues));
+            InternalSend(new ArraySegment<byte>(data, 0, data.Length));
+        }
+
+        #endregion
+
+        #region Receiving processing
+
+        /// <summary>
+        /// Sets the next Receive filter which will be used when next data block received
+        /// </summary>
+        /// <param name="nextReceiveFilter">The next receive filter.</param>
+        protected void SetNextReceiveFilter(IReceiveFilter<TRequestInfo> nextReceiveFilter)
+        {
+            m_ReceiveFilter = nextReceiveFilter;
+        }
+
+        /// <summary>
+        /// Gets the maximum allowed length of the request.
+        /// </summary>
+        /// <returns></returns>
+        protected virtual int GetMaxRequestLength()
+        {
+            return AppServer.Config.MaxRequestLength;
+        }
+
+        /// <summary>
+        /// Filters the request.
+        /// </summary>
+        /// <param name="readBuffer">The read buffer.</param>
+        /// <param name="offset">The offset.</param>
+        /// <param name="length">The length.</param>
+        /// <param name="toBeCopied">if set to <c>true</c> [to be copied].</param>
+        /// <param name="rest">The rest, the size of the data which has not been processed</param>
+        /// <param name="offsetDelta">return offset delta of next receiving buffer.</param>
+        /// <returns></returns>
+        TRequestInfo FilterRequest(byte[] readBuffer, int offset, int length, bool toBeCopied, out int rest, out int offsetDelta)
+        {
+            if (!AppServer.OnRawDataReceived(this, readBuffer, offset, length))
+            {
+                rest = 0;
+                offsetDelta = 0;
+                return null;
+            }
+
+            var currentRequestLength = m_ReceiveFilter.LeftBufferSize;
+
+            var requestInfo = m_ReceiveFilter.Filter(readBuffer, offset, length, toBeCopied, out rest);
+
+            if (m_ReceiveFilter.State == FilterState.Error)
+            {
+                rest = 0;
+                offsetDelta = 0;
+                Close(CloseReason.ProtocolError);
+                return null;
+            }
+
+            var offsetAdapter = m_ReceiveFilter as IOffsetAdapter;
+
+            offsetDelta = offsetAdapter != null ? offsetAdapter.OffsetDelta : 0;
+
+            if (requestInfo == null)
+            {
+                //current buffered length
+                currentRequestLength = m_ReceiveFilter.LeftBufferSize;
+            }
+            else
+            {
+                //current request length
+                currentRequestLength = currentRequestLength + length - rest;
+            }
+
+            var maxRequestLength = GetMaxRequestLength();
+
+            if (currentRequestLength >= maxRequestLength)
+            {
+                if (Logger.IsErrorEnabled)
+                    Logger.Error(this, string.Format("Max request length: {0}, current processed length: {1}", maxRequestLength, currentRequestLength));
+
+                Close(CloseReason.ProtocolError);
+                return null;
+            }
+
+            //If next Receive filter wasn't set, still use current Receive filter in next round received data processing
+            if (m_ReceiveFilter.NextReceiveFilter != null)
+                m_ReceiveFilter = m_ReceiveFilter.NextReceiveFilter;
+
+            return requestInfo;
+        }
+
+        /// <summary>
+        /// Processes the request data.
+        /// </summary>
+        /// <param name="readBuffer">The read buffer.</param>
+        /// <param name="offset">The offset.</param>
+        /// <param name="length">The length.</param>
+        /// <param name="toBeCopied">if set to <c>true</c> [to be copied].</param>
+        /// <returns>
+        /// return offset delta of next receiving buffer
+        /// </returns>
+        int IAppSession.ProcessRequest(byte[] readBuffer, int offset, int length, bool toBeCopied)
+        {
+            int rest, offsetDelta;
+
+            while (true)
+            {
+                var requestInfo = FilterRequest(readBuffer, offset, length, toBeCopied, out rest, out offsetDelta);
+
+                if (requestInfo != null)
+                {
+                    try
+                    {
+                        AppServer.ExecuteCommand(this, requestInfo);
+                    }
+                    catch (Exception e)
+                    {
+                        HandleException(e);
+                    }
+                }
+
+                if (rest <= 0)
+                {
+                    return offsetDelta;
+                }
+
+                //Still have data has not been processed
+                offset = offset + length - rest;
+                length = rest;
+            }
+        }
+
+        #endregion
+    }
+
+    /// <summary>
+    /// AppServer basic class for whose request infoe type is StringRequestInfo
+    /// </summary>
+    /// <typeparam name="TAppSession">The type of the app session.</typeparam>
+    public abstract class AppSession<TAppSession> : AppSession<TAppSession, StringRequestInfo>
+        where TAppSession : AppSession<TAppSession, StringRequestInfo>, IAppSession, new()
+    {
+
+        private bool m_AppendNewLineForResponse = false;
+
+        private static string m_NewLine = "\r\n";
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppSession&lt;TAppSession&gt;"/> class.
+        /// </summary>
+        public AppSession()
+            : this(true)
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppSession&lt;TAppSession&gt;"/> class.
+        /// </summary>
+        /// <param name="appendNewLineForResponse">if set to <c>true</c> [append new line for response].</param>
+        public AppSession(bool appendNewLineForResponse)
+        {
+            m_AppendNewLineForResponse = appendNewLineForResponse;
+        }
+
+        /// <summary>
+        /// Handles the unknown request.
+        /// </summary>
+        /// <param name="requestInfo">The request info.</param>
+        protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
+        {
+            Send("Unknown request: " + requestInfo.Key);
+        }
+
+        /// <summary>
+        /// Processes the sending message.
+        /// </summary>
+        /// <param name="rawMessage">The raw message.</param>
+        /// <returns></returns>
+        protected virtual string ProcessSendingMessage(string rawMessage)
+        {
+            if (!m_AppendNewLineForResponse)
+                return rawMessage;
+
+            if (AppServer.Config.Mode == SocketMode.Udp)
+                return rawMessage;
+
+            if (string.IsNullOrEmpty(rawMessage) || !rawMessage.EndsWith(m_NewLine))
+                return rawMessage + m_NewLine;
+            else
+                return rawMessage;
+        }
+
+        /// <summary>
+        /// Sends the specified message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <returns></returns>
+        public override void Send(string message)
+        {
+            base.Send(ProcessSendingMessage(message));
+        }
+
+        /// <summary>
+        /// Sends the response.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <param name="paramValues">The param values.</param>
+        /// <returns>Indicate whether the message was pushed into the sending queue</returns>
+        public override void Send(string message, params object[] paramValues)
+        {
+            base.Send(ProcessSendingMessage(message), paramValues);
+        }
+    }
+
+    /// <summary>
+    /// AppServer basic class for whose request infoe type is StringRequestInfo
+    /// </summary>
+    public class AppSession : AppSession<AppSession>
+    {
+
+    }
+}

+ 143 - 0
SocketBase.backup/Async.cs

@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SuperSocket.SocketBase.Logging;
+
+namespace SuperSocket.SocketBase
+{
+    /// <summary>
+    /// Async extension class
+    /// </summary>
+    public static class Async
+    {
+        /// <summary>
+        /// Runs the specified task.
+        /// </summary>
+        /// <param name="logProvider">The log provider.</param>
+        /// <param name="task">The task.</param>
+        /// <returns></returns>
+        public static Task AsyncRun(this ILoggerProvider logProvider, Action task)
+        {
+            return AsyncRun(logProvider, task, TaskCreationOptions.None);
+        }
+
+        /// <summary>
+        /// Runs the specified task.
+        /// </summary>
+        /// <param name="logProvider">The log provider.</param>
+        /// <param name="task">The task.</param>
+        /// <param name="taskOption">The task option.</param>
+        /// <returns></returns>
+        public static Task AsyncRun(this ILoggerProvider logProvider, Action task, TaskCreationOptions taskOption)
+        {
+            return AsyncRun(logProvider, task, taskOption, null);
+        }
+
+        /// <summary>
+        /// Runs the specified task.
+        /// </summary>
+        /// <param name="logProvider">The log provider.</param>
+        /// <param name="task">The task.</param>
+        /// <param name="exceptionHandler">The exception handler.</param>
+        /// <returns></returns>
+        public static Task AsyncRun(this ILoggerProvider logProvider, Action task, Action<Exception> exceptionHandler)
+        {
+            return AsyncRun(logProvider, task, TaskCreationOptions.None, exceptionHandler);
+        }
+
+        /// <summary>
+        /// Runs the specified task.
+        /// </summary>
+        /// <param name="logProvider">The log provider.</param>
+        /// <param name="task">The task.</param>
+        /// <param name="taskOption">The task option.</param>
+        /// <param name="exceptionHandler">The exception handler.</param>
+        /// <returns></returns>
+        public static Task AsyncRun(this ILoggerProvider logProvider, Action task, TaskCreationOptions taskOption, Action<Exception> exceptionHandler)
+        {
+            return Task.Factory.StartNew(task, taskOption).ContinueWith(t =>
+                {
+                    if (exceptionHandler != null)
+                        exceptionHandler(t.Exception);
+                    else
+                    {
+                        if (logProvider.Logger.IsErrorEnabled)
+                        {
+                            for (var i = 0; i < t.Exception.InnerExceptions.Count; i++)
+                            {
+                                logProvider.Logger.Error(t.Exception.InnerExceptions[i]);
+                            }
+                        }
+                    }
+                }, TaskContinuationOptions.OnlyOnFaulted);
+        }
+
+        /// <summary>
+        /// Runs the specified task.
+        /// </summary>
+        /// <param name="logProvider">The log provider.</param>
+        /// <param name="task">The task.</param>
+        /// <param name="state">The state.</param>
+        /// <returns></returns>
+        public static Task AsyncRun(this ILoggerProvider logProvider, Action<object> task, object state)
+        {
+            return AsyncRun(logProvider, task, state, TaskCreationOptions.None);
+        }
+
+        /// <summary>
+        /// Runs the specified task.
+        /// </summary>
+        /// <param name="logProvider">The log provider.</param>
+        /// <param name="task">The task.</param>
+        /// <param name="state">The state.</param>
+        /// <param name="taskOption">The task option.</param>
+        /// <returns></returns>
+        public static Task AsyncRun(this ILoggerProvider logProvider, Action<object> task, object state, TaskCreationOptions taskOption)
+        {
+            return AsyncRun(logProvider, task, state, taskOption, null);
+        }
+
+        /// <summary>
+        /// Runs the specified task.
+        /// </summary>
+        /// <param name="logProvider">The log provider.</param>
+        /// <param name="task">The task.</param>
+        /// <param name="state">The state.</param>
+        /// <param name="exceptionHandler">The exception handler.</param>
+        /// <returns></returns>
+        public static Task AsyncRun(this ILoggerProvider logProvider, Action<object> task, object state, Action<Exception> exceptionHandler)
+        {
+            return AsyncRun(logProvider, task, state, TaskCreationOptions.None, exceptionHandler);
+        }
+
+        /// <summary>
+        /// Runs the specified task.
+        /// </summary>
+        /// <param name="logProvider">The log provider.</param>
+        /// <param name="task">The task.</param>
+        /// <param name="state">The state.</param>
+        /// <param name="taskOption">The task option.</param>
+        /// <param name="exceptionHandler">The exception handler.</param>
+        /// <returns></returns>
+        public static Task AsyncRun(this ILoggerProvider logProvider, Action<object> task, object state, TaskCreationOptions taskOption, Action<Exception> exceptionHandler)
+        {
+            return Task.Factory.StartNew(task, state, taskOption).ContinueWith(t =>
+            {
+                if (exceptionHandler != null)
+                    exceptionHandler(t.Exception);
+                else
+                {
+                    if (logProvider.Logger.IsErrorEnabled)
+                    {
+                        for (var i = 0; i < t.Exception.InnerExceptions.Count; i++)
+                        {
+                            logProvider.Logger.Error(t.Exception.InnerExceptions[i]);
+                        }
+                    }
+                }
+            }, TaskContinuationOptions.OnlyOnFaulted);
+        }
+    }
+}

+ 53 - 0
SocketBase.backup/Command/CommandBase.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SuperSocket.SocketBase.Protocol;
+
+namespace SuperSocket.SocketBase.Command
+{
+    /// <summary>
+    /// Command base class
+    /// </summary>
+    /// <typeparam name="TAppSession">The type of the app session.</typeparam>
+    /// <typeparam name="TRequestInfo">The type of the request info.</typeparam>
+    public abstract class CommandBase<TAppSession, TRequestInfo> : ICommand<TAppSession, TRequestInfo>
+        where TAppSession : IAppSession, IAppSession<TAppSession, TRequestInfo>, new()
+        where TRequestInfo : IRequestInfo
+    {
+
+        #region ICommand<TAppSession,TRequestInfo> Members
+
+        /// <summary>
+        /// Executes the command.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="requestInfo">The request info.</param>
+        public abstract void ExecuteCommand(TAppSession session, TRequestInfo requestInfo);
+
+        #endregion
+
+        #region ICommand Members
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        public virtual string Name
+        {
+            get { return this.GetType().Name; }
+        }
+
+        #endregion
+
+        /// <summary>
+        /// Returns a <see cref="System.String" /> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String" /> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return this.GetType().AssemblyQualifiedName;
+        }
+    }
+}

+ 39 - 0
SocketBase.backup/Command/CommandInfo.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SuperSocket.SocketBase.Metadata;
+
+namespace SuperSocket.SocketBase.Command
+{
+    class CommandInfo<TCommand>
+        where TCommand : ICommand
+    {
+        public TCommand Command { get; private set; }
+
+        public CommandFilterAttribute[] Filters { get; private set; }
+
+        public CommandInfo(TCommand command, IEnumerable<CommandFilterAttribute> globalFilters)
+        {
+            Command = command;
+
+            var allFilters = new List<CommandFilterAttribute>();
+
+            if (globalFilters != null && globalFilters.Any())
+            {
+                allFilters.AddRange(globalFilters);
+            }
+
+            IEnumerable<CommandFilterAttribute> filters = command is ICommandFilterProvider ?
+                (command as ICommandFilterProvider).GetFilters() : AppServer.GetCommandFilterAttributes(command.GetType());
+
+            if (filters != null && filters.Any())
+                allFilters.AddRange(filters);
+
+            if (allFilters.Any())
+            {
+                Filters = allFilters.OrderBy(f => f.Order).ToArray();
+            }
+        }
+    }
+}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác