فهرست منبع

add
Signed-off-by: wangwei <wangwei@persagy.com>

wangwei 4 سال پیش
والد
کامیت
e6ddff0547
100فایلهای تغییر یافته به همراه18848 افزوده شده و 0 حذف شده
  1. 81 0
      Config/online/Client.exe.config
  2. 8 0
      Config/online/MBIRevitBase.dll.config
  3. 81 0
      Config/test/Client.exe.config
  4. 8 0
      Config/test/MBIRevitBase.dll.config
  5. 149 0
      Dispatcher/Client/Client.csproj
  6. 129 0
      Dispatcher/Client/ClientApp.cs
  7. 90 0
      Dispatcher/Client/ClientInfo.cs
  8. 20 0
      Dispatcher/Client/IRevitCommandExcutor.cs
  9. 50 0
      Dispatcher/Client/MainClass.cs
  10. 113 0
      Dispatcher/Client/MessageHandler.cs
  11. 36 0
      Dispatcher/Client/Properties/AssemblyInfo.cs
  12. 63 0
      Dispatcher/Client/Readme.txt
  13. 41 0
      Dispatcher/Client/Start/CustomMessage.cs
  14. 161 0
      Dispatcher/Client/Start/RevitCmdExecutor.cs
  15. 41 0
      Dispatcher/Client/Start/ServiceMBIClientHandler.cs
  16. 197 0
      Dispatcher/Client/TaskHandler.cs
  17. 82 0
      Dispatcher/Client/app.config
  18. 72 0
      Dispatcher/Client/packages.config
  19. 149 0
      Dispatcher/HttpDownload/DownloadTask.cs
  20. 51 0
      Dispatcher/HttpDownload/HttpDownload.csproj
  21. 298 0
      Dispatcher/HttpDownload/HttpDownloader.cs
  22. 184 0
      Dispatcher/HttpDownload/LimitedConcurrencyLevelTaskScheduler.cs
  23. 36 0
      Dispatcher/HttpDownload/Properties/AssemblyInfo.cs
  24. 128 0
      Dispatcher/HttpDownload/TaskDownloadManager.cs
  25. 13 0
      Dispatcher/NettyClient/ClientWrapper.cs
  26. 139 0
      Dispatcher/NettyClient/NettyClient.csproj
  27. 36 0
      Dispatcher/NettyClient/Properties/AssemblyInfo.cs
  28. 84 0
      Dispatcher/NettyClient/SimpleMessageHandler.cs
  29. 111 0
      Dispatcher/NettyClient/TaskNettyClient.cs
  30. 75 0
      Dispatcher/NettyClient/app.config
  31. 72 0
      Dispatcher/NettyClient/packages.config
  32. 229 0
      Dispatcher/NettyClient/proto/MessageProto.cs
  33. 225 0
      Dispatcher/NettyClient/proto/MessageProto.cs-bak
  34. 29 0
      Dispatcher/NettyClient/proto/MessageUtil.cs
  35. 79 0
      Dispatcher/ServiceMBI.sln
  36. BIN
      Dispatcher/TaskDatabase/FakesAssemblies/Remotion.Linq.Fakes.dll
  37. BIN
      Dispatcher/TaskDatabase/FakesAssemblies/Remotion.Linq.Fakes.fakesconfig
  38. 258 0
      Dispatcher/TaskDatabase/FakesAssemblies/Remotion.Linq.Fakes.messages
  39. 11450 0
      Dispatcher/TaskDatabase/FakesAssemblies/Remotion.Linq.Fakes.xml
  40. 41 0
      Dispatcher/TaskDatabase/Mappings/TaskModel.hbm.xml
  41. 22 0
      Dispatcher/TaskDatabase/Model/DownloadTaskModel.cs
  42. 32 0
      Dispatcher/TaskDatabase/Model/TaskModel.cs
  43. 42 0
      Dispatcher/TaskDatabase/NHibernateHelper.cs
  44. 36 0
      Dispatcher/TaskDatabase/Properties/AssemblyInfo.cs
  45. 95 0
      Dispatcher/TaskDatabase/TaskDatabase.csproj
  46. 214 0
      Dispatcher/TaskDatabase/TaskService.cs
  47. 11 0
      Dispatcher/TaskDatabase/hibernate.cfg.xml
  48. 9 0
      Dispatcher/TaskDatabase/packages.config
  49. 85 0
      Executer/DataCheck/CheckFactory.cs
  50. 40 0
      Executer/DataCheck/Common/MBIConst.cs
  51. 46 0
      Executer/DataCheck/Common/RegexConstPattern.cs
  52. 59 0
      Executer/DataCheck/DataCheck.Mode/CheckBase.cs
  53. 56 0
      Executer/DataCheck/DataCheck.Mode/ColumnCheck.cs
  54. 26 0
      Executer/DataCheck/DataCheck.Mode/ColumnCheckResult.cs
  55. 168 0
      Executer/DataCheck/DataCheck.Mode/ConnectorCheck.cs
  56. 30 0
      Executer/DataCheck/DataCheck.Mode/ConnectorCheckResult.cs
  57. 268 0
      Executer/DataCheck/DataCheck.Mode/ElementRangeCheck.cs
  58. 36 0
      Executer/DataCheck/DataCheck.Mode/ElementRangeCheckResult.cs
  59. 74 0
      Executer/DataCheck/DataCheck.Mode/EquipInSpaceCheck.cs
  60. 32 0
      Executer/DataCheck/DataCheck.Mode/EquipInSpaceCheckResult.cs
  61. 61 0
      Executer/DataCheck/DataCheck.Mode/EquipPartLocationCheck.cs
  62. 25 0
      Executer/DataCheck/DataCheck.Mode/EquipPartLocationCheckResult.cs
  63. 84 0
      Executer/DataCheck/DataCheck.Mode/FamilyNameCheck.cs
  64. 21 0
      Executer/DataCheck/DataCheck.Mode/FamilyNameCheckResult.cs
  65. 86 0
      Executer/DataCheck/DataCheck.Mode/ParameterIntegrityCheck.cs
  66. 22 0
      Executer/DataCheck/DataCheck.Mode/ParameterIntegrityCheckResult.cs
  67. 150 0
      Executer/DataCheck/DataCheck.Mode/PipeCheck.cs
  68. 26 0
      Executer/DataCheck/DataCheck.Mode/PipeCheckResult.cs
  69. 35 0
      Executer/DataCheck/DataCheck.Mode/ResultBase.cs
  70. 17 0
      Executer/DataCheck/DataCheck.Mode/ResultState.cs
  71. 100 0
      Executer/DataCheck/DataCheck.Mode/SagaCheck.cs
  72. 21 0
      Executer/DataCheck/DataCheck.Mode/SagaCheckResult.cs
  73. 97 0
      Executer/DataCheck/DataCheck.Mode/SystemNameCheck.cs
  74. 26 0
      Executer/DataCheck/DataCheck.Mode/SystemNameCheckResult.cs
  75. 131 0
      Executer/DataCheck/DataCheck.Mode/SystemReferEquipCheck.cs
  76. 38 0
      Executer/DataCheck/DataCheck.Mode/SystemReferEquipCheckResult.cs
  77. 55 0
      Executer/DataCheck/DataCheck.Mode/UnitCheck.cs
  78. 21 0
      Executer/DataCheck/DataCheck.Mode/UnitCheckResult.cs
  79. 77 0
      Executer/DataCheck/DataCheck.Mode/XYZOverlapCheck.cs
  80. BIN
      Executer/DataCheck/DataCheckResource/模型检查结果输出格式-模版.xlsx
  81. 38 0
      Executer/DataCheck/Extend/DocExtend.cs
  82. 244 0
      Executer/DataCheck/Extend/ElementExtend.cs
  83. 48 0
      Executer/DataCheck/Extend/MepExtension.cs
  84. 37 0
      Executer/DataCheck/Extend/SpaceExtend.cs
  85. 36 0
      Executer/DataCheck/Properties/AssemblyInfo.cs
  86. 132 0
      Executer/DataCheck/ServiceDataCheck.csproj
  87. 64 0
      Executer/DataCheck/TestCommand.cs
  88. 166 0
      Executer/DataCheck/Utils/DataCheckRule.cs
  89. 23 0
      Executer/DataCheck/app.config
  90. 6 0
      Executer/DataCheck/packages.config
  91. 49 0
      Executer/DataExport/JBIM.sln
  92. 96 0
      Executer/DataExport/JBIM/BimDocument.cs
  93. 74 0
      Executer/DataExport/JBIM/BimId.cs
  94. 51 0
      Executer/DataExport/JBIM/BimObject.cs
  95. 68 0
      Executer/DataExport/JBIM/Common/BimObjectUtil.cs
  96. 37 0
      Executer/DataExport/JBIM/Common/EnumExtensions.cs
  97. 37 0
      Executer/DataExport/JBIM/Common/PropertyCache.cs
  98. 34 0
      Executer/DataExport/JBIM/Common/TypeDefinitonAttribute.cs
  99. 25 0
      Executer/DataExport/JBIM/Common/TypeDefinitonUtil.cs
  100. 0 0
      Executer/DataExport/JBIM/Component/BoundarySegment.cs

+ 81 - 0
Config/online/Client.exe.config

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <appSettings>
+    <add key="IP" value="47.94.89.44"/>
+    <add key="Port" value="6666"/>
+    <add key="DownloadFileDir" value="E:\\"/>
+    <add key="MaxTaskCount" value="3"/>
+    <add key="MaxDownloadTaskCount" value="6"/>
+  </appSettings>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-3.8.0.0" newVersion="3.8.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options.ConfigurationExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Transport" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Buffers" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Common" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Codecs" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="11.0.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+  <startup>
+    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+  </startup>
+</configuration>

+ 8 - 0
Config/online/MBIRevitBase.dll.config

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+  <appSettings>
+    <add key="IP" value="http://mbi.sagacloud.cn"/>
+    <add key="Port" value="8080"/>
+    <add key="Path" value="/revit-algorithm/upload-json-zip/upload"/>
+  </appSettings>
+</configuration>

+ 81 - 0
Config/test/Client.exe.config

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <appSettings>
+    <add key="IP" value="172.16.42.210"/>
+    <add key="Port" value="6666"/>
+    <add key="DownloadFileDir" value="E:\\"/>
+    <add key="MaxTaskCount" value="3"/>
+    <add key="MaxDownloadTaskCount" value="6"/>
+  </appSettings>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-3.8.0.0" newVersion="3.8.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options.ConfigurationExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Transport" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Buffers" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Common" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Codecs" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="11.0.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+  <startup>
+    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+  </startup>
+</configuration>

+ 8 - 0
Config/test/MBIRevitBase.dll.config

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+  <appSettings>
+    <add key="IP" value="http://172.16.42.210"/>
+    <add key="Port" value="8082"/>
+    <add key="Path" value="/upload-json-zip/upload"/>
+  </appSettings>
+</configuration>

+ 149 - 0
Dispatcher/Client/Client.csproj

@@ -0,0 +1,149 @@
+<?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>{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Client</RootNamespace>
+    <AssemblyName>Client</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\OutputDll\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="DotNetty.Buffers, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Buffers.0.6.0\lib\net45\DotNetty.Buffers.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Common, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Common.0.6.0\lib\net45\DotNetty.Common.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Transport, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Transport.0.6.0\lib\net45\DotNetty.Transport.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Protobuf, Version=3.8.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Google.Protobuf.3.8.0\lib\net45\Google.Protobuf.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Binder, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Logging.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Logging.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Options, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Options.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Primitives, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Primitives.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Newtonsoft.Json.11.0.1\lib\net45\Newtonsoft.Json.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.5.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.Composition" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
+    </Reference>
+    <Reference Include="System.IO.Compression.FileSystem" />
+    <Reference Include="System.Management" />
+    <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.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+    </Reference>
+    <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.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MainClass.cs" />
+    <Compile Include="ClientApp.cs" />
+    <Compile Include="ClientInfo.cs" />
+    <Compile Include="IRevitCommandExcutor.cs" />
+    <Compile Include="MessageHandler.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Start\CustomMessage.cs" />
+    <Compile Include="Start\RevitCmdExecutor.cs" />
+    <Compile Include="Start\ServiceMBIClientHandler.cs" />
+    <Compile Include="TaskHandler.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="packages.config">
+      <SubType>Designer</SubType>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Readme.txt" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\HttpDownload\HttpDownload.csproj">
+      <Project>{9f423033-98a9-4b6b-9bb1-f1aa8c648a02}</Project>
+      <Name>HttpDownload</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\NettyClient\NettyClient.csproj">
+      <Project>{7a08d4e8-a171-47bd-a527-bc9ba1833305}</Project>
+      <Name>NettyClient</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\TaskDatabase\TaskDatabase.csproj">
+      <Project>{ade36aa5-fca8-4e5b-a27e-2360884404b3}</Project>
+      <Name>TaskDatabase</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 129 - 0
Dispatcher/Client/ClientApp.cs

@@ -0,0 +1,129 @@
+using HttpDownload;
+using NettyClient;
+using NettyClient.proto;
+using System;
+using System.Threading;
+using TaskDatabase;
+
+namespace Client
+{
+    public class ClientApp
+    {
+        static TaskNettyClient client;                    // 网络传输客户端
+        static SimpleMessageHandler simpleHandler;        // 网络传输处理
+        TaskService taskService;                   // 持久化任务
+        TaskDownloadManager taskDownloadManager;   // 下载任务文件(Http)
+        MessageHandler messageHandler;             // 处理客户端收到的消息
+        TaskHandler taskHandler;                   // 处理服务端发送的任务(监视下载状况等待)
+        int maxTaskCount;                          // 能处理的最大任务数量, 影响是否拒绝服务器分发的任务
+        string defaultFileDir;                     // 默认文件目录
+        private Action<int> heartbeat;
+        IRevitCommandExcutor revitCommandExcutor;
+        private Action<int> reconnectAction;
+        public ClientApp(string ip, int port, string dir, int maxTaskCount, IRevitCommandExcutor revitCommandExcutor, int maxDownTaskCount=5) {
+            client = new TaskNettyClient(ip, port);
+            taskService = new TaskService();
+            taskDownloadManager = new TaskDownloadManager(maxDownTaskCount);
+            this.maxTaskCount = maxTaskCount;
+            defaultFileDir = dir;
+            this.revitCommandExcutor = revitCommandExcutor;
+        }
+
+        public void Start() {
+            
+            simpleHandler = new SimpleMessageHandler();
+            if (messageHandler == null)
+            {
+                taskHandler = new TaskHandler(simpleHandler, taskService, taskDownloadManager, defaultFileDir, revitCommandExcutor);
+                taskHandler.SyncAllTask();
+                messageHandler = new MessageHandler(simpleHandler, maxTaskCount, taskHandler);
+                messageHandler.ResumeAllTasks();
+                ThreadPool.QueueUserWorkItem(messageHandler.HandleMessage);
+                ThreadPool.QueueUserWorkItem(taskHandler.RunTasks);
+            }
+            else
+            {
+                messageHandler.setSimpleMessageHandler(simpleHandler);
+                taskHandler.setSimpleMessageHandler(simpleHandler);
+            }
+
+            // 起动心跳线程
+            heartbeat = SendHeartbeat;
+            heartbeat.BeginInvoke(0, null, null);
+
+            client.RunClientAsync(simpleHandler).Wait();
+
+            reconnectAction = Reconnect;
+            reconnectAction.BeginInvoke(30, null, null);
+        }
+
+        void Reconnect(int interval)
+        {
+            while (true)
+            {
+                Thread.Sleep(interval * 1000);
+                if (!TaskNettyClient.isConnected)
+                {
+                    Console.WriteLine(DateTime.Now + ": reconnecting....");
+                    Restart();
+                }
+            }
+        }
+
+        void SendHeartbeat(int nouse)
+        {
+            while (true)
+            {
+                try
+                {
+                    Thread.Sleep(30000);
+                    var retMsg = MessageUtil.generateMessageStr(Command.Useless.ToString(), "", "{}");
+                    simpleHandler.WriteMessage(retMsg);
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine(e);
+                    Thread.Sleep(300*1000);
+                }
+            }
+        }
+
+        public void Close() {
+            client.CloseAsync().Wait();
+        }
+
+        public void PauseAllTask() {
+            taskDownloadManager.pauseAllTasks();
+            messageHandler.PauseAllTasks();
+        }
+        public void ResumeAllTask()
+        {
+            taskDownloadManager.resumeAllTasks();
+            messageHandler.ResumeAllTasks();
+        }
+
+        public void Restart()
+        {
+            simpleHandler = new SimpleMessageHandler();
+            if (messageHandler == null)
+            {
+                taskHandler = new TaskHandler(simpleHandler, taskService, taskDownloadManager, defaultFileDir, revitCommandExcutor);
+                taskHandler.SyncAllTask();
+                messageHandler = new MessageHandler(simpleHandler, maxTaskCount, taskHandler);
+                messageHandler.ResumeAllTasks();
+                
+                ThreadPool.QueueUserWorkItem(messageHandler.HandleMessage);
+                ThreadPool.QueueUserWorkItem(taskHandler.RunTasks);
+            }
+            else
+            {
+                messageHandler.setSimpleMessageHandler(simpleHandler);
+                taskHandler.setSimpleMessageHandler(simpleHandler);
+            }
+
+            client.RunClientAsync(simpleHandler).Wait();
+        }
+    }
+
+    
+}

+ 90 - 0
Dispatcher/Client/ClientInfo.cs

@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Management;
+using System.Net;
+
+namespace Client
+{
+    public class ClientInfo
+    {
+        public string MacAddr { get; set; }
+        public string Ipv4 { get; set; }
+        public string Name { get; set; }
+    }
+    public class ClientInfoUtil {
+        /// <summary>  
+        /// 获取本机MAC地址  
+        /// </summary>  
+        /// <returns>本机MAC地址</returns>  
+        public static string GetMacAddress()
+        {
+            try
+            {
+                string strMac = string.Empty;
+                ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
+                ManagementObjectCollection moc = mc.GetInstances();
+                foreach (ManagementObject mo in moc)
+                {
+                    if ((bool)mo["IPEnabled"] == true)
+                    {
+                        strMac = mo["MacAddress"].ToString();
+                    }
+                }
+                moc = null;
+                mc = null;
+                return strMac;
+            }
+            catch
+            {
+                return "unknown";
+            }
+        }
+        /// <summary>  
+        /// 操作系统的登录用户名  
+        /// </summary>  
+        /// <returns>系统的登录用户名</returns>  
+        public static string GetUserName()
+        {
+            try
+            {
+                return $"{Environment.MachineName}\\{Environment.UserName}";
+                //string strUserName = string.Empty;
+                //ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
+                //ManagementObjectCollection moc = mc.GetInstances();
+                //foreach (ManagementObject mo in moc)
+                //{
+                //    strUserName = mo["UserName"].ToString();
+                //}
+                //moc = null;
+                //mc = null;
+                //return strUserName;
+            }
+            catch
+            {
+                return "unknown";
+            }
+        }
+        /// <summary>  
+        /// 获取客户端内网IPv4地址  
+        /// </summary>  
+        /// <returns>客户端内网IPv4地址</returns>  
+        public static string GetClientLocalIPv4Address()
+        {
+            string strLocalIP = string.Empty;
+            try
+            {
+                IPHostEntry ipHost = Dns.Resolve(Dns.GetHostName());
+                IPAddress ipAddress = ipHost.AddressList[0];
+                strLocalIP = ipAddress.ToString();
+                return strLocalIP;
+            }
+            catch
+            {
+                return "unknown";
+            }
+        }
+    }
+}

+ 20 - 0
Dispatcher/Client/IRevitCommandExcutor.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Client
+{
+    public interface IRevitCommandExcutor
+    {
+        /// <summary>
+        /// 执行Revit命令
+        /// </summary>
+        /// <param name="revitCmd">被执行的Revit命令</param>
+        /// <param name="param">执行命令的参数</param>
+        /// <param name="filePathList">用到的文件的路径</param>
+        /// <returns>任务执行结果返回json格式字符串</returns>
+        string ExecuteCmd(string revitCmd, string param, HashSet<string> filePathList, string taskId);
+    }
+}

+ 50 - 0
Dispatcher/Client/MainClass.cs

@@ -0,0 +1,50 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Windows.Forms;
+using Client.Start;
+
+namespace Client
+{
+    public class MainClass
+    {
+        public static void Main()
+        {
+            try
+            {
+                //Client后台运行
+                //new MainClass();
+                ServiceMBIClientHandler.Start();
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+            while (true)
+                Console.ReadKey();
+        }
+        [DllImport("User32.dll", EntryPoint = "FindWindow")]
+        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
+
+        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]   //找子窗体   
+        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
+
+        [DllImport("User32.dll", EntryPoint = "SendMessage")]   //用于发送信息给窗体   
+        private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);
+
+        [DllImport("User32.dll", EntryPoint = "ShowWindow")]   //
+        private static extern bool ShowWindow(IntPtr hWnd, int type);
+
+        public MainClass()
+        {
+            Console.Title = "MyConsoleApp";
+            IntPtr ParenthWnd = new IntPtr(0);
+            IntPtr et = new IntPtr(0);
+            ParenthWnd = FindWindow(null, "MyConsoleApp");
+
+            ShowWindow(ParenthWnd, 1);//隐藏本dos窗体, 0: 后台执行;1:正常启动;2:最小化到任务栏;3:最大化
+
+
+        }
+    }
+}

+ 113 - 0
Dispatcher/Client/MessageHandler.cs

@@ -0,0 +1,113 @@
+using NettyClient;
+using Message = Cn.Sagacloud.Proto.Message;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using NettyClient.proto;
+
+namespace Client
+{
+    class MessageHandler
+    {
+        private SimpleMessageHandler simpleHandler;
+        private TaskHandler taskHandler;
+        private bool isPauseTask = false;
+        private int maxTaskCount;
+        public MessageHandler(SimpleMessageHandler simpleHandler, int maxTaskCount, TaskHandler taskHandler) {
+            this.simpleHandler = simpleHandler;
+            this.maxTaskCount = maxTaskCount;
+            this.taskHandler = taskHandler;
+        }
+        public void setSimpleMessageHandler(SimpleMessageHandler simpleHandler) {
+            this.simpleHandler = simpleHandler;
+        }
+        public void HandleMessage(object obj) {
+            while (true) {
+                Message message;
+                bool hasMsg = SimpleMessageHandler.messageQueue.TryDequeue(out message);
+                if (!hasMsg) {
+                    Thread.Sleep(500);
+                    continue;
+                }
+                Command command = Command.Useless;
+                try
+                {
+                     command = (Command)Enum.Parse(typeof(Command), message.Cmd);
+                }
+                catch { command = Command.Useless; }
+                Message retMsg;
+                switch (command) {
+                    case Command.SendTask:
+                        // 1. 检测是否接受该任务 
+                        if (checkIsAcceptTask(message.TaskId))
+                        {
+                            // 2. 如果接受, 保存任务到数据库, 并同步该任务到内存, 并交由任务执行线程开始执行
+                            bool isSuccess = taskHandler.addOneTask(message.TaskId, message.Content);
+                            if (isSuccess)
+                            {
+                                retMsg = MessageUtil.generateMessageStr(Command.AcceptTask.ToString(), message.TaskId, "");
+                                simpleHandler.WriteMessage(retMsg);
+                            }
+                        }
+                        else {
+                            // 3. 如果拒绝, 直接返回拒绝消息
+                            retMsg = MessageUtil.generateMessageStr(Command.RefuseTask.ToString(), message.TaskId, "");
+                            simpleHandler.WriteMessage(retMsg);
+                        }
+                        break;
+                    case Command.ClientInfo: // 服务端要求客户端返回客户端信息
+                        ClientInfo info = new ClientInfo();
+                        info.Ipv4 = ClientInfoUtil.GetClientLocalIPv4Address();
+                        info.MacAddr = ClientInfoUtil.GetMacAddress();
+                        info.Name = ClientInfoUtil.GetUserName();
+                        retMsg = MessageUtil.generateMessageStr(Command.ClientInfo.ToString(), "", JsonConvert.SerializeObject(info, Formatting.None));
+                        simpleHandler.WriteMessage(retMsg);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        private bool checkIsAcceptTask(string taskId)
+        {
+            //一. isPauseTask == true的时候拒绝任务, 二. 如果已存在该任务, 则拒绝, 三. 如果当前任务数达到maxTaskCount, 拒绝
+            if (isPauseTask)
+                return false;
+            if (taskHandler.isContainTask(taskId)) {
+                return false;
+            }
+            if (taskHandler.taskModels.Count >= maxTaskCount)
+                return false;
+            return true;
+
+
+        }
+
+        internal void PauseAllTasks()
+        {
+            isPauseTask = true;
+        }
+
+        internal void ResumeAllTasks()
+        {
+            isPauseTask = false;
+        }
+    }
+
+    enum Command
+    {
+        SendTask,
+        RefuseTask,
+        AcceptTask,
+        DownloadError,
+        CommandError,
+        TaskSuccess,
+        ClientInfo,
+        Useless
+    }
+}

+ 36 - 0
Dispatcher/Client/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("Client")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Client")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("6a52af44-63c6-4ab6-92d4-2a05173d45fb")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 63 - 0
Dispatcher/Client/Readme.txt

@@ -0,0 +1,63 @@
+用到的dll
+DotNetty.Transport (>= 0.6.0)
+DotNetty.Buffers (>= 0.6.0)
+DotNetty.Common (>= 0.6.0)
+Microsoft.Extensions.Logging (1.1.0)
+Microsoft.Extensions.Logging.Abstractions 使用最新版本
+
+DotNetty.Codecs.Protobuf
+DotNetty.Codecs
+
+Google.Protobuf 使用最新版本3.7.0
+
+数据库
+
+Mysql.Data 8.0
+NHibernate  5.2.5
+
+
+
+JSON
+newtonsoft.json 11.0.1,注意版本,12.0.*可能会出现问题,很坑的
+
+
+传入的参数有:
+CommandName;
+MBIName,ModelId,ResultFileName;
+Floor
+结果存储在:ResultFileName中
+ResultFileName的地址为Local+"RevitService"+guid
+使用完成会将结果删除
+最终的结果将存储在客户端JsonResult中
+
+
+192.168.20.225:6666  是调度器的socket地址
+数据库是 192.168.20.235 : 5432     数据库名 datacenter.scheduler, 你要是添加数据, 可以直接在这里加, 是postgresql数据库
+
+
+调度时,需要手动启动本机的mysql
+
+
+
+服务器端表:
+PostgreSql 数据库是 192.168.20.235 : 5432
+数据库名:datacenter.scheduler,包含两个表download,task
+task_name ,task名称,随便填
+task_cmd,Revit需要执行的命令,
+task_param,命令需要的参数,
+task_status,命令的状态,'0 Waiting, 1 Sending, 2 Sent, 3 FileDownloadException, 4 CommandExecuteException, 5 Finished',
+task_expected_finish_time,预期完成时间,单位s,指定时间未完成,任务超时。
+
+down表
+task_id关联任务的id,上面生成的id
+task_url,文件的存储地址,文件服务器地址
+task_md5,目前可以不填 ,目前 没有进行md5校验
+
+本地数据库表
+mysql:localhost_3306 用户名:root,密码:123456
+数据库名:worker,包含两个表download,task
+task.task_status,0 Waiting, 1 Success, -1 downloadError, -2 execute error
+
+重新执行某个命令
+本地数据库task_status更改为0
+重启客户端

+ 41 - 0
Dispatcher/Client/Start/CustomMessage.cs

@@ -0,0 +1,41 @@
+/* ==============================================================================
+ * 功能描述:自定义消息
+ * 创 建 者:Garrett
+ * 创建日期:2019/4/12 11:55:31
+ * ==============================================================================*/
+
+namespace Client.Start
+{
+    /// <summary>
+    /// DotMessage
+    /// </summary>
+    class CustomMessage
+    {
+        public CustomMessage(bool mResult, string mResultMsg)
+        {
+            m_Result = mResult;
+            m_ResultMsg = mResultMsg;
+        }
+        private bool m_Result;
+        /// <summary>
+        /// 状态,暂定为bool类型
+        /// </summary>
+        public bool Result
+        {
+            get { return m_Result; }
+            set { m_Result = value; }
+        }
+
+        private string m_ResultMsg;
+        /// <summary>
+        /// 消息提示
+        /// </summary>
+        public string ResultMsg
+        {
+            get { return m_ResultMsg; }
+            set { m_ResultMsg = value; }
+        }
+
+
+    }
+}

+ 161 - 0
Dispatcher/Client/Start/RevitCmdExecutor.cs

@@ -0,0 +1,161 @@
+/* ==============================================================================
+ * 功能描述:RevitCmdExecutor  
+ * 创 建 者:Garrett
+ * 创建日期:2019/4/16 11:46:37
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Windows.Forms;
+using Newtonsoft.Json.Linq;
+using System.Threading;
+
+namespace Client.Start
+{
+    /// <summary>
+    /// RevitCmdExecutor
+    /// </summary>
+    public class RevitCmdExecutor : IRevitCommandExcutor
+    {
+        public string ExecuteCmd(string revitCmd, string param, HashSet<string> filePathList, string taskId)
+        {
+            string msg = null;
+            try
+            {
+                //由revitCmd生成实体类
+                //实体类传入参数、参考楼层列表
+                //执行方法,返回执行结果 
+                Console.WriteLine(DateTime.Now + " 准备执行命令:" + revitCmd);
+                string fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StartVisionSelector.exe");
+                Process process = new Process();//AppDomain.CurrentDomain.BaseDirectory +
+                process.StartInfo.FileName = fullPath;//执行的exe路径
+                process.StartInfo.UseShellExecute = false;//不显示shell
+                process.StartInfo.CreateNoWindow = true;//不创建窗口
+                process.StartInfo.RedirectStandardInput = true;//打开流输入
+                process.StartInfo.RedirectStandardOutput = true;//打开流输出
+                process.StartInfo.RedirectStandardError = true;//打开错误流
+                string resultFilePath = GetReusltFileName(taskId, revitCmd);
+                string newParam = AddResultFileNameToParam(param, resultFilePath);
+                Console.WriteLine(filePathList.First());
+                //输入参数,多个参数使用空间分割,如果一个参数包含空格,使用""包括此参数
+                //注意Json的传入格式
+                process.StartInfo.Arguments = revitCmd + " " +
+                                              "\"" + newParam + "\"" + " " +
+                                              "\"" + filePathList.First() + "\"";
+                process.Start();//执行
+                process.WaitForExit();
+                //string msg = process.StandardOutput.ReadToEnd();//读取输出
+                //try
+                //{
+                //    while (process != null && !process.HasExited)
+                //    {
+                //        process.WaitForExit(60 * 1000); //等待执行完成
+                //        if (!process.HasExited && File.Exists(resultFilePath))
+                //        {
+                //            Thread.Sleep(5000);
+                //            if (process != null && !process.HasExited)
+                //            {
+                //                //process.Close();
+                //                //process = null;
+                //                //process.Kill();
+                //                //process.Dispose();
+
+                //            }
+                //        }
+                //    }
+                //}
+                //catch(Exception ex)
+                //{
+                //    Console.WriteLine(ex.Message + "\r\n" + ex.StackTrace);
+                //}
+                msg = ReadResultString(resultFilePath);
+                
+                Console.WriteLine(DateTime.Now + " 命令执行完成:" + revitCmd);
+#if !DEBUG
+                //执行完成后,删除文件
+                foreach (var f in filePathList)
+                {
+                    File.Delete(f);
+                }
+#endif
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine(e.Message + "\r\n" + e.StackTrace);
+            }
+
+            return msg;
+        }
+        /// <summary>
+        /// 将检查结果的保存位置添加到参数中
+        /// </summary>
+        /// <param name="param"></param>
+        /// <param name="fileName"></param>
+        /// <returns></returns>
+        private string AddResultFileNameToParam(string param, string filePath)
+        {
+
+            JObject jObject = null;
+            if (string.IsNullOrEmpty(param))
+            {
+                jObject = new JObject();
+            }
+            else
+            {
+                jObject = JObject.Parse(param);
+            };
+            string key = "ResultFileName";
+            jObject.Add(new JProperty(key, filePath));
+            return jObject.ToString().Replace("\"", "\\\"");
+        }
+        /// <summary>
+        /// 生成 结果的保存文件名
+        /// </summary>
+        /// <returns></returns>
+        private string GetReusltFileName(string taskId, string revitCmd)
+        {
+            string localPath = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+            // string fileName = "Result_" + Guid.NewGuid().ToString() + ".txt";
+            string fileName = "Result_" + taskId + revitCmd + ".txt";
+            return Path.Combine(localPath, "RevitService", fileName);
+        }
+        /// <summary>
+        /// 读取执行的结果,并清理结果文件
+        /// </summary>
+        /// <param name="filePath"></param>
+        /// <returns></returns>
+        private string ReadResultString(string filePath)
+        {
+            Console.WriteLine(filePath);
+            string str = "";
+
+            Console.WriteLine("read file try times: ");
+            int retryTimes = 0;
+            while (!File.Exists(filePath) && retryTimes < 30)
+            {
+                Thread.Sleep(10000);
+                retryTimes++;
+            }
+
+            if (File.Exists(filePath))
+            {
+                retryTimes = 0;
+                do
+                {
+                    Thread.Sleep(3000);
+                    str = File.ReadAllText(filePath);
+                    retryTimes++;
+                    Console.WriteLine("read file try times: " + retryTimes);
+                } while ((str == null || str.Length == 0) && retryTimes < 100);
+#if !DEBUG
+                File.Delete(filePath);
+#endif
+            }
+            Console.WriteLine("read file try times: ");
+            return str;
+        }
+    }
+}

+ 41 - 0
Dispatcher/Client/Start/ServiceMBIClientHandler.cs

@@ -0,0 +1,41 @@
+/* ==============================================================================
+ * 功能描述:ServiceMBIClientHandler  
+ * 创 建 者:Garrett
+ * 创建日期:2019/4/12 15:08:46
+ * ==============================================================================*/
+
+using System;
+using System.Windows.Forms;
+using TaskDatabase;
+using TaskDatabase.Model;
+using System.Configuration;
+
+namespace Client.Start
+{
+    /// <summary>
+    /// ServiceMBIClientHandler
+    /// </summary>
+    public class ServiceMBIClientHandler
+    {
+        private static ClientApp m_Client;
+        public static void Start()
+        {
+            string ip = ConfigurationManager.AppSettings["IP"];
+            Console.WriteLine(ip);
+            int port = Convert.ToInt32(ConfigurationManager.AppSettings["Port"]);
+            string dir = ConfigurationManager.AppSettings["DownloadFileDir"];
+            int maxtask = Convert.ToInt32(ConfigurationManager.AppSettings["MaxTaskCount"]);
+            int maxDownloadTask = Convert.ToInt32(ConfigurationManager.AppSettings["MaxDownloadTaskCount"]);
+            //192.168.20.225
+            m_Client = new ClientApp(ip, port, dir, maxtask, new RevitCmdExecutor(), maxDownloadTask);
+            m_Client.Start();
+            //Console.WriteLine("begin");
+            //Console.ReadKey();
+        }
+
+        public static void Stop()
+        {
+            m_Client?.Close();
+        }
+    }
+}

+ 197 - 0
Dispatcher/Client/TaskHandler.cs

@@ -0,0 +1,197 @@
+using HttpDownload;
+using NettyClient;
+using NettyClient.proto;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using TaskDatabase;
+using TaskDatabase.Model;
+
+namespace Client
+{
+    class TaskHandler
+    {
+        private SimpleMessageHandler simpleHandler;
+        private TaskService taskService;
+        public IList<TaskModel> taskModels;
+        private TaskDownloadManager taskDownloadManager;
+        private string defaultFileDir;
+        IRevitCommandExcutor revitCommandExcutor;
+
+        public void RunTasks(object obj) {
+            while (true) {
+                try
+                {
+                    if (taskModels == null) continue;
+                    for (int i = taskModels.Count - 1; i > -1; --i) {
+                        TaskModel task = taskModels[i];
+                        TaskModel downloadException = null, commandException = null;
+                        bool isAllDownloaded = true;
+                        // 看当前任务依赖的文件下载状况
+                        foreach (DownloadTaskModel downloadTaskModel in task.DownloadTaskModelList) {
+                            DownloadTask download = taskDownloadManager.getDownloadTaskByDownloadTaskId(downloadTaskModel.Task_id);
+                            if (download == null) // 如果还未加入下载队列
+                            {
+                                // 开始下载
+                                if (downloadTaskModel.Local_dir == null) {
+                                    downloadTaskModel.Local_dir = defaultFileDir + downloadTaskModel.Task_id + ".rvt";
+                                } 
+                                download = taskDownloadManager.enqueueTask(task.Id, downloadTaskModel.Task_url,
+                                    downloadTaskModel.Local_dir, downloadTaskModel.Task_md5, downloadTaskModel.Downloaded_bytes);
+                                taskDownloadManager.runTask(download);
+                                isAllDownloaded &= false;
+                            }
+                            else {
+                                // 如果该下载发生异常
+                                if (download.Status == DownloadStatus.ExceptionStopped) {
+                                    isAllDownloaded &= false;
+                                    downloadException = task;
+                                    break;
+                                }
+                                // 同步当前状态到数据库
+                                if (download.Status == DownloadStatus.Completed)
+                                {
+                                    downloadTaskModel.Finish_time = GetTimeStampSeconds();
+                                    isAllDownloaded &= true;
+                                }
+                                else {
+                                    isAllDownloaded &= false;
+                                }
+                                syncSingleDownTask(download, downloadTaskModel);
+                            }
+                        } // foreach end
+                        // 如果该下载任务下载失败
+                        if (downloadException != null)
+                        {
+                            task.Task_status = -1;
+                            taskService.UpdateTask(task);
+                            taskModels.RemoveAt(i);
+                            simpleHandler.WriteMessage(MessageUtil.generateMessageStr(Command.DownloadError.ToString(), task.Id, ""));
+                            continue;
+                        }
+                        // 如果该任务的所有下载文件均已完成, 开始执行Revit命令
+                        if (isAllDownloaded) {
+                            try
+                            {
+                                HashSet<string> fileSet = new HashSet<string>();
+                                foreach (var downloadModel in task.DownloadTaskModelList) {
+                                    fileSet.Add(downloadModel.Local_dir);
+                                }
+                                try
+                                {
+                                    
+                                    string resultJson = revitCommandExcutor.ExecuteCmd(task.Task_cmd, task.Task_param, fileSet, task.Id);
+                                    simpleHandler.WriteMessage(MessageUtil.generateMessageStr(Command.TaskSuccess.ToString(), task.Id, resultJson));
+                                    task.Task_status = 1;
+                                    task.Task_result_json = resultJson;
+                                    taskService.UpdateTask(task);
+                                    taskModels.RemoveAt(i);
+                                }
+                                catch(Exception ex) {
+                                    Console.WriteLine(ex.StackTrace);
+                                    commandException = task;
+                                }
+                            }
+                            catch(Exception ex) {
+                                Console.WriteLine(ex.StackTrace);
+                            }
+                        }
+                        if (commandException != null)
+                        {
+                            task.Task_status = -2;
+                            taskService.UpdateTask(task);
+                            taskModels.RemoveAt(i);
+                            simpleHandler.WriteMessage(MessageUtil.generateMessageStr(Command.CommandError.ToString(), task.Id, ""));
+                            continue;
+                        }
+                    }
+                    taskService.removeErrorTask();
+                }
+                catch (Exception ex){
+                    Console.WriteLine(ex.StackTrace);
+                }
+                finally { 
+                    Thread.Sleep(3*1000);
+                }
+
+            }
+        }
+
+        private void syncSingleDownTask(DownloadTask downTask, DownloadTaskModel downloadModel)
+        {
+            bool changed = false;
+            if (downloadModel.Downloaded_bytes != downTask.BytesWritten)
+            {
+                downloadModel.Downloaded_bytes = downTask.BytesWritten;
+                changed = true;
+            }
+            if (downloadModel.File_bytes != downTask.totalFileSize)
+            {
+                downloadModel.File_bytes = downTask.totalFileSize;
+                changed = true;
+            }
+            if(changed)
+                taskService.UpdateDownload(downloadModel);
+        }
+
+        public void setSimpleMessageHandler(SimpleMessageHandler simpleHandler)
+        {
+            this.simpleHandler = simpleHandler;
+        }
+
+        private TaskHandler(SimpleMessageHandler simpleHandler, TaskService taskService)
+        {
+            this.simpleHandler = simpleHandler;
+            this.taskService = taskService;
+        }
+
+        public TaskHandler(SimpleMessageHandler simpleHandler, TaskService taskService, TaskDownloadManager taskDownloadManager, string defaultFileDir, IRevitCommandExcutor revitCommandExcutor) : this(simpleHandler, taskService)
+        {
+            this.taskDownloadManager = taskDownloadManager;
+            this.defaultFileDir = defaultFileDir;
+            this.revitCommandExcutor = revitCommandExcutor;
+        }
+    
+        internal void SyncAllTask()
+        {
+            IList<TaskModel> tasks = taskService.GetTasksByStatus(0); // 任务状态 0 未执行完的任务, 1 执行完成  -1 下载出错  -2 revit命令执行异常
+            taskModels = tasks;
+        }
+        internal bool addOneTask(string taskId, string msgContent) {
+            try
+            {
+                TaskModel taskModel = JsonConvert.DeserializeObject<TaskModel>(msgContent);
+                taskService.AddTask(taskModel);
+                TaskModel task = taskService.GetTasksByTaskId(taskId)[0];
+                taskModels.Add(task);
+                foreach (DownloadTaskModel download in taskModel.DownloadTaskModelList) {
+                    download.Local_dir = defaultFileDir + download.Task_id + ".rvt";
+                    taskService.UpdateDownload(download);
+                }
+                return true;
+            }
+            catch(Exception ex) {
+                Console.WriteLine(ex.Message+ex.StackTrace);
+                return false;
+            }
+        }
+
+        internal bool isContainTask(string taskId)
+        {
+            try
+            {
+                return taskService.isContainsTask(taskId);
+            }
+            catch (Exception ex){
+                Console.WriteLine(ex.StackTrace);
+                return true;
+            }
+        }
+
+        public static long GetTimeStampSeconds() {
+            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
+            return (long)ts.TotalSeconds;
+        }
+    }
+}

+ 82 - 0
Dispatcher/Client/app.config

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <appSettings>
+    <!--<add key="IP" value="172.16.42.210" />-->
+    <add key="IP" value="47.94.89.44" />
+    <add key="Port" value="6666" />
+    <add key="DownloadFileDir" value="E:\\" />
+    <add key="MaxTaskCount" value="3" />
+    <add key="MaxDownloadTaskCount" value="6" />
+  </appSettings>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-3.8.0.0" newVersion="3.8.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options.ConfigurationExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Transport" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Buffers" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Common" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Codecs" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="11.0.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+  <startup>
+    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+  </startup>
+</configuration>

+ 72 - 0
Dispatcher/Client/packages.config

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="BouncyCastle" version="1.8.3.1" targetFramework="net461" />
+  <package id="DotNetty.Buffers" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Common" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Transport" version="0.6.0" targetFramework="net461" />
+  <package id="Google.Protobuf" version="3.8.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration.Binder" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Logging" version="1.1.1" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Logging.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Options" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Primitives" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net461" />
+  <package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="MySql.Data" version="8.0.18" targetFramework="net461" />
+  <package id="NETStandard.Library" version="1.6.1" targetFramework="net461" />
+  <package id="Newtonsoft.Json" version="11.0.1" targetFramework="net461" />
+  <package id="SSH.NET" version="2016.1.0" targetFramework="net461" />
+  <package id="System.AppContext" version="4.3.0" targetFramework="net461" />
+  <package id="System.Buffers" version="4.4.0" targetFramework="net461" />
+  <package id="System.Collections" version="4.3.0" targetFramework="net461" />
+  <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
+  <package id="System.ComponentModel" version="4.3.0" targetFramework="net461" />
+  <package id="System.ComponentModel.Annotations" version="4.5.0" targetFramework="net461" />
+  <package id="System.Console" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net461" />
+  <package id="System.Globalization" version="4.3.0" targetFramework="net461" />
+  <package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Linq" version="4.3.0" targetFramework="net461" />
+  <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Memory" version="4.5.2" targetFramework="net461" />
+  <package id="System.Net.Http" version="4.3.0" targetFramework="net461" />
+  <package id="System.Net.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Net.Sockets" version="4.3.0" targetFramework="net461" />
+  <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net461" />
+  <package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net461" />
+  <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.Handles" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net461" />
+  <package id="System.Threading.Timer" version="4.3.0" targetFramework="net461" />
+  <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
+  <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
+</packages>

+ 149 - 0
Dispatcher/HttpDownload/DownloadTask.cs

@@ -0,0 +1,149 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HttpDownload
+{
+    public class DownloadTask
+    {
+        public string BelongingId { get; set; }     // 任务id
+        //public int DownloadTaskId { get; set; }
+        public string FileUrl { get; }
+        public string FileDir { get; }
+        public long Offset { get; } // 开始下载的位置
+        public string ExpectedMD5 { get; }
+
+        private volatile DownloadStatus status;
+        public DownloadStatus Status { get { return status; } }
+        private string exceptionInfo;
+        public string ExceptionInfo { get { return exceptionInfo; } } //  保存发生异常时的Message
+        private double percentage = 0d;
+        private HttpDownloader httpDownloader = null;
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="fileUrl"></param>
+        /// <param name="fileDir"></param>
+        /// <param name="expectedMD5"></param>
+        /// <param name="offset">如果 offset == -1, 则把已写入文件的字节数当作offset</param>
+        public DownloadTask(string fileUrl, string fileDir, string expectedMD5, long offset = 0L)
+        {
+            this.FileUrl = fileUrl;
+            this.FileDir = fileDir;
+            this.Offset = offset;
+            this.ExpectedMD5 = expectedMD5;
+            status = DownloadStatus.Created;
+            exceptionInfo = string.Empty;
+            httpDownloader = new HttpDownloader(fileUrl, fileDir, offset);
+
+        }
+
+        public DownloadTask(string taskId, string fileUrl, string fileDir, string expectedMD5, long offset = 0L)
+        {
+            this.BelongingId = taskId;
+            this.FileUrl = fileUrl;
+            this.FileDir = fileDir;
+            this.Offset = offset;
+            this.ExpectedMD5 = expectedMD5;
+            status = DownloadStatus.Created;
+            exceptionInfo = string.Empty;
+            httpDownloader = new HttpDownloader(fileUrl, fileDir, offset);
+        }
+
+
+        internal static void download(DownloadTask dTask)
+        {
+            try
+            {
+                if (dTask.status.Equals(DownloadStatus.Paused))
+                    return;
+                dTask.status = DownloadStatus.Processing;
+                dTask.httpDownloader.DownloadFile();
+                if (dTask.httpDownloader.running)
+                    dTask.status = DownloadStatus.Completed;
+            }
+            catch (Exception ex)
+            {
+                dTask.status = DownloadStatus.ExceptionStopped;
+                dTask.exceptionInfo = ex.Message;
+            }
+        }
+
+        public string calculateMD5()
+        {
+            if (Status.Equals(DownloadStatus.Completed))
+            {
+                string md5Digest = "";
+                return md5Digest;
+            }
+            return null;
+        }
+
+        public void pauseTask()
+        {
+            if (status == DownloadStatus.Completed)
+                return;
+            httpDownloader.running = false;
+            status = DownloadStatus.Paused;
+        }
+        public void resumeTask()
+        {
+            if (!httpDownloader.running)
+            {
+                httpDownloader.running = true;
+                status = DownloadStatus.WaitToRun;
+            }
+        }
+        public bool isFinished()
+        {
+            return httpDownloader.Finished;
+        }
+        public string getFileName()
+        {
+            return Path.GetFileName(FileDir);
+        }
+
+        public long totalFileSize
+        {
+            get
+            {
+                if (httpDownloader != null)
+                    return httpDownloader.TotalRemoteFileSize;
+                return 0;
+            }
+        }
+        public long BytesWritten
+        {
+            get
+            {
+                if (httpDownloader != null)
+                    return httpDownloader.BytesWritten;
+                return 0;
+            }
+        }
+        public string getSpeed(bool isFormatted)
+        {
+            if (httpDownloader != null && DownloadStatus.Processing.Equals(status))
+                return httpDownloader.getSpeed(isFormatted);
+            return "0 B/s";
+        }
+        public double getPercentage(int decimals)
+        {
+            if (httpDownloader != null)
+                return httpDownloader.getPercentage(decimals);
+            return 0d;
+        }
+    }
+    public enum DownloadStatus
+    {
+        Created, // 初始状态
+        WaitToRun, // 进入队列等待被执行 
+        Paused,    // 已暂停
+        Processing,// 正在执行
+        Completed, // 完成
+        ExceptionStopped // 出现异常已暂停
+    }
+}

+ 51 - 0
Dispatcher/HttpDownload/HttpDownload.csproj

@@ -0,0 +1,51 @@
+<?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>{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HttpDownload</RootNamespace>
+    <AssemblyName>HttpDownload</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\OutputDll\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <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="DownloadTask.cs" />
+    <Compile Include="HttpDownloader.cs" />
+    <Compile Include="LimitedConcurrencyLevelTaskScheduler.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TaskDownloadManager.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 298 - 0
Dispatcher/HttpDownload/HttpDownloader.cs

@@ -0,0 +1,298 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.IO;
+using System.Net;
+using System.Threading;
+
+namespace HttpDownload
+{
+    class HttpDownloader
+    {
+        const int bytebuff = 4096;
+        const int ReadWriteTimeOut = 10 * 1000;// 在写入超时或读取超时之前的毫秒数
+        const int TimeOutWait = 10 * 1000;// 请求超时前等待的毫秒数
+        const int MaxTryTime = 10; // 最大重试次数
+        int currentRetryTimes = 0;
+        private bool finished = false;
+        public bool Finished { get { return finished; } }
+        private long totalRemoteFileSize = 0L; // 要下载的文件的总大小
+        public long TotalRemoteFileSize { get { return totalRemoteFileSize; } }
+        public long BytesWritten { get { return offset; } }
+
+        string url, destPath;
+        private long offset, timeStamp, bytesAtTimeStamp;
+        volatile private int speed;
+        FileStream fs;
+        internal volatile bool running = false;
+
+
+        public HttpDownloader(string url, string destPath, long offset = 0)
+        {
+            this.destPath = destPath;
+            this.url = url;
+            this.offset = offset;
+        }
+
+        public void DownloadFile()
+        {
+            if (isDownloadFinished(offset))
+            {
+                return;
+            }
+
+            bool hasError = true;
+            int retryTimes = 200;
+            while (hasError && retryTimes > 0)
+            {
+                try
+                {
+                    hasError = false;
+                    for (; !finished && running;)
+                        HttpDownloadFile();
+                }
+                catch (Exception ex)
+                {
+                    hasError = true;
+                    --retryTimes;
+                    if(retryTimes <= 0)
+                        throw ex;
+                }
+            }
+        }
+        const string errorInfo = "下载结束, 但是文件长度与下载字节数不一致!";
+        /// <summary>
+        /// 下载文件(同步)  支持断点续传
+        /// </summary>
+        private bool HttpDownloadFile()
+        {
+            //打开上次下载的文件
+            //long lStartPos = 0;
+            fs = getFileStream();
+            HttpWebRequest request = null;
+            WebResponse respone = null;
+            Stream ns = null;
+            try
+            {
+                request = (HttpWebRequest)WebRequest.Create(url);
+                request.ReadWriteTimeout = ReadWriteTimeOut;
+                request.Timeout = TimeOutWait;
+                if (offset > 0)
+                    request.AddRange(offset);//设置Range值,断点续传
+
+                //向服务器请求,获得服务器回应数据流
+                respone = request.GetResponse();
+                ns = respone.GetResponseStream();
+                byte[] nbytes = new byte[bytebuff];
+                int nReadSize = ns.Read(nbytes, 0, bytebuff);
+                if (timeStamp == 0)
+                {
+                    timeStamp = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds);
+                    bytesAtTimeStamp = offset;
+                }
+                while (nReadSize > 0 && running)
+                {
+                    long now = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds);
+                    if (now - timeStamp >= 1000)
+                    {
+                        long dataDiff = offset - bytesAtTimeStamp, timeDiff = now - timeStamp;
+                        speed = (int)(dataDiff * 1000 / timeDiff);     // 1000是由ms转为s
+                        timeStamp = now;
+                        bytesAtTimeStamp = offset;
+                    }
+                    fs.Write(nbytes, 0, nReadSize);
+                    fs.Flush();
+                    offset += nReadSize;
+                    //Thread.Sleep(20);
+                    nReadSize = ns.Read(nbytes, 0, bytebuff);
+                }
+                if (!running)
+                    return true;
+                if (offset != totalRemoteFileSize && running)//文件长度不等于下载长度,下载出错
+                {
+                    throw new Exception(errorInfo);
+                }
+                if (running)
+                    finished = true;
+            }
+            catch (Exception ex)
+            {
+                if (ex.Message.Equals(errorInfo))
+                    throw ex;
+                ++currentRetryTimes;
+                if (currentRetryTimes > MaxTryTime)
+                {
+                    throw ex;
+                }
+            }
+            finally
+            {
+                if (ns != null)
+                    ns.Close();
+                if (fs != null)
+                    fs.Close();
+                if (request != null)
+                    request.Abort();
+            }
+            return false;
+        }
+
+        private FileStream getFileStream()
+        {
+            if (fs != null)
+            {
+                fs.Close();
+            }
+            if (File.Exists(destPath))
+            {
+                fs = File.OpenWrite(destPath);
+                // offset < 0 则按照文件的大小定为offset
+                if (offset < 0)
+                {
+                    offset = fs.Length;
+                }
+                fs.Seek(offset, SeekOrigin.Current);//移动文件流中的当前指针
+            }
+            else
+            {
+                string dirName = Path.GetDirectoryName(destPath);
+
+                if (!Directory.Exists(dirName))//如果不存在保存文件夹路径,新建文件夹
+                {
+                    Directory.CreateDirectory(dirName);
+                }
+                fs = new FileStream(destPath, FileMode.Create);
+                offset = 0;
+            }
+            return fs;
+        }
+
+        /// <summary>
+        /// 获取下载文件长度
+        /// </summary>
+        /// <param name="url"></param>
+        /// <returns></returns>
+        public static long GetFileContentLength(string url)
+        {
+            HttpWebRequest request = null;
+            int retryTimes = 200;
+            while (retryTimes > 0)
+            {
+                try
+                {
+                    --retryTimes;
+                    request = (HttpWebRequest) HttpWebRequest.Create(url);
+                    request.Timeout = TimeOutWait;
+                    request.ReadWriteTimeout = ReadWriteTimeOut;
+                    //向服务器请求,获得服务器回应数据流
+                    WebResponse respone = request.GetResponse();
+                    request.Abort();
+                    return respone.ContentLength;
+                }
+                catch (Exception e)
+                {
+                    if (request != null)
+                        request.Abort();
+                }
+                Thread.Sleep(100);
+            }
+            return -1;
+        }
+        private bool isDownloadFinished(long offset)
+        {
+            if (finished)
+                return true;
+            if (totalRemoteFileSize == 0)
+                totalRemoteFileSize = GetFileContentLength(url);
+            if (totalRemoteFileSize != 0 && totalRemoteFileSize == offset)
+            {
+                //下载完成
+                finished = true;
+                return true;
+            }
+            return false;
+        }
+        /// <summary>
+        /// 获取当前速度
+        /// </summary>
+        /// <param name="formatted"></param>
+        /// <returns></returns>
+        public string getSpeed(bool formatted)
+        {
+            if (formatted)
+            {
+                if (finished)
+                    return "0 kB/s";
+                else
+                {
+                    return formatSpeed(speed, 0L, 0);
+                }
+            }
+            else
+            {
+                if (finished)
+                    return "0";
+                else
+                    return speed + "";
+            }
+        }
+        private string formatSpeed(long speed, long decimalDigit, int depth)
+        {
+            if (speed < 1024)
+            {
+                return handleDigit(speed, decimalDigit) + getUnitByDepth(depth);
+            }
+            else
+            {
+                return formatSpeed(speed / 1024, speed % 1024, depth + 1);
+            }
+        }
+        private string handleDigit(long integer, long decimalDigit)
+        {
+            if (decimalDigit == 0)
+            {
+                return integer.ToString();
+            }
+            else
+            {
+                return integer.ToString() + Math.Round((double)decimalDigit / 1024, 1).ToString().Substring(1);
+            }
+        }
+        private string getUnitByDepth(int depth)
+        {
+            string val = string.Empty;
+            switch (depth)
+            {
+                case 0:
+                    val = " B/s";
+                    break;
+                case 1:
+                    val = " kB/s";
+                    break;
+                case 2:
+                    val = " MB/s";
+                    break;
+                case 3:
+                    val = " GB/s";
+                    break;
+                default:
+                    val = " unknown/s";
+                    break;
+            }
+            return val;
+        }
+        public double getPercentage(int decimals)
+        {
+            if (totalRemoteFileSize == 0L)
+            {
+                return Math.Round(0d, decimals);
+            }
+            if (finished)
+                return Math.Round(100d, decimals);
+            double percentage = (double)offset * 100d / totalRemoteFileSize;
+            return Math.Round(percentage, decimals);
+        }
+    }
+}

+ 184 - 0
Dispatcher/HttpDownload/LimitedConcurrencyLevelTaskScheduler.cs

@@ -0,0 +1,184 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace HttpDownload
+{
+    class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
+    {
+        /// <summary>Whether the current thread is processing work items.</summary>
+        [ThreadStatic]
+        private static bool _currentThreadIsProcessingItems;
+        /// <summary>The list of tasks to be executed.</summary>
+        private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
+                                                                           /// <summary>The maximum concurrency level allowed by this scheduler.</summary>
+        private readonly int _maxDegreeOfParallelism;
+        /// <summary>Whether the scheduler is currently processing work items.</summary>
+        private int _delegatesQueuedOrRunning = 0; // protected by lock(_tasks)
+
+        /// <summary>
+        /// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the
+        /// specified degree of parallelism.
+        /// </summary>
+        /// <param name="maxDegreeOfParallelism">The maximum degree of parallelism provided by this scheduler.</param>
+        public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
+        {
+            if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
+            _maxDegreeOfParallelism = maxDegreeOfParallelism;
+        }
+
+        /// <summary>Queues a task to the scheduler.</summary>
+        /// <param name="task">The task to be queued.</param>
+        protected sealed override void QueueTask(Task task)
+        {
+            // Add the task to the list of tasks to be processed.  If there aren't enough
+            // delegates currently queued or running to process tasks, schedule another.
+            lock (_tasks)
+            {
+                _tasks.AddLast(task);
+                if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
+                {
+                    ++_delegatesQueuedOrRunning;
+                    NotifyThreadPoolOfPendingWork();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Informs the ThreadPool that there's work to be executed for this scheduler.
+        /// </summary>
+        private void NotifyThreadPoolOfPendingWork()
+        {
+            ThreadPool.UnsafeQueueUserWorkItem(_ =>
+            {
+                // Note that the current thread is now processing work items.
+                // This is necessary to enable inlining of tasks into this thread.
+                _currentThreadIsProcessingItems = true;
+                try
+                {
+                    // Process all available items in the queue.
+                    while (true)
+                    {
+                        Task item;
+                        lock (_tasks)
+                        {
+                            // When there are no more items to be processed,
+                            // note that we're done processing, and get out.
+                            if (_tasks.Count == 0)
+                            {
+                                --_delegatesQueuedOrRunning;
+                                break;
+                            }
+
+                            // Get the next item from the queue
+                            item = _tasks.First.Value;
+                            _tasks.RemoveFirst();
+                        }
+
+                        // Execute the task we pulled out of the queue
+                        base.TryExecuteTask(item);
+                    }
+                }
+                // We're done processing items on the current thread
+                finally { _currentThreadIsProcessingItems = false; }
+            }, null);
+        }
+
+        /// <summary>Attempts to execute the specified task on the current thread.</summary>
+        /// <param name="task">The task to be executed.</param>
+        /// <param name="taskWasPreviouslyQueued"></param>
+        /// <returns>Whether the task could be executed on the current thread.</returns>
+        protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
+        {
+            // If this thread isn't already processing a task, we don't support inlining
+            if (!_currentThreadIsProcessingItems) return false;
+
+            // If the task was previously queued, remove it from the queue
+            if (taskWasPreviouslyQueued) TryDequeue(task);
+
+            // Try to run the task.
+            return base.TryExecuteTask(task);
+        }
+
+        /// <summary>Attempts to remove a previously scheduled task from the scheduler.</summary>
+        /// <param name="task">The task to be removed.</param>
+        /// <returns>Whether the task could be found and removed.</returns>
+        protected sealed override bool TryDequeue(Task task)
+        {
+            lock (_tasks) return _tasks.Remove(task);
+        }
+
+        /// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
+        public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }
+
+        /// <summary>Gets an enumerable of the tasks currently scheduled on this scheduler.</summary>
+        /// <returns>An enumerable of the tasks currently scheduled.</returns>
+        protected sealed override IEnumerable<Task> GetScheduledTasks()
+        {
+            bool lockTaken = false;
+            try
+            {
+                Monitor.TryEnter(_tasks, ref lockTaken);
+                if (lockTaken) return _tasks.ToArray();
+                else throw new NotSupportedException();
+            }
+            finally
+            {
+                if (lockTaken) Monitor.Exit(_tasks);
+            }
+        }
+    }
+    class TaskFactoryMananger
+    {
+        //USE
+        public static void Run()
+        {
+
+            try
+            {
+                while (true)
+                {
+                    LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(10);
+                    TaskFactory factory = new TaskFactory(lcts);
+                    Task[] spiderTask = new Task[] {
+                        factory.StartNew(() =>
+                        {
+                            //Log.Logger.Information("{0} Start on thread {1}", "111", Thread.CurrentThread.ManagedThreadId);
+                            //Log.Logger.Information("{0} Finish  on thread {1}", "111", Thread.CurrentThread.ManagedThreadId);
+                        }),
+                        factory.StartNew(() =>
+                        {
+                            Thread.Sleep(TimeSpan.FromSeconds(3));
+                            //Log.Logger.Information("{0} Start on thread {1}", "222", Thread.CurrentThread.ManagedThreadId);
+                            //Log.Logger.Information("{0} Finish  on thread {1}", "222", Thread.CurrentThread.ManagedThreadId);
+                        }),
+                        factory.StartNew(() =>
+                        {
+                            Thread.Sleep(TimeSpan.FromSeconds(5));
+                            //Log.Logger.Information("{0} Start on thread {1}", "333", Thread.CurrentThread.ManagedThreadId);
+                            //Log.Logger.Information("{0} Finish  on thread {1}", "333", Thread.CurrentThread.ManagedThreadId);
+                        })
+                        };
+                    Task.WaitAll(spiderTask);
+                    Thread.Sleep(TimeSpan.FromMinutes(1));
+                }
+            }
+            catch (AggregateException ex)
+            {
+                foreach (Exception inner in ex.InnerExceptions)
+                {
+                    //Log.Logger.Error(inner.Message);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Provides a task scheduler that ensures a maximum concurrency level while
+        /// running on top of the ThreadPool.
+        /// </summary>
+
+    }
+}

+ 36 - 0
Dispatcher/HttpDownload/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("HttpDownload")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HttpDownload")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("9f423033-98a9-4b6b-9bb1-f1aa8c648a02")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 128 - 0
Dispatcher/HttpDownload/TaskDownloadManager.cs

@@ -0,0 +1,128 @@
+using System;
+using System.Collections;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HttpDownload
+{
+    public class TaskDownloadManager
+    {
+        public int Capacity { get; set; }
+
+        // DownloadTask list
+        ArrayList allTasks = new ArrayList();
+
+        LimitedConcurrencyLevelTaskScheduler lcts = null;
+        TaskFactory factory = null;
+
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="count">最大同时任务数[1, 30], 异常为5</param>
+        public TaskDownloadManager(int count)
+        {
+            //ThreadPool.SetMaxThreads(count, count);
+            if (count >= 1 && count <= 30)
+                Capacity = count;
+            else
+                Capacity = 5;
+            lcts = new LimitedConcurrencyLevelTaskScheduler(Capacity);
+            factory = new TaskFactory(lcts);
+        }
+        /// <summary>
+        /// 添加任务到队列
+        /// </summary>
+        /// <param name="fileUrl">文件的下载地址</param>
+        /// <param name="fileDir">文件再本地的保存路径</param>
+        /// <param name="offset">在文件中开始下载的的位置, byte</param>
+        /// <returns>任务</returns>
+        public DownloadTask enqueueTask(string fileUrl, string fileDir, string expectedMD5, long offset = 0L)
+        {
+            DownloadTask task = new DownloadTask(fileUrl, fileDir, expectedMD5, offset);
+            allTasks.Add(task);
+            return task;
+        }
+        public DownloadTask enqueueTask(string taskId, string fileUrl, string fileDir, string expectedMD5, long offset = 0L)
+        {
+            DownloadTask task = new DownloadTask(taskId, fileUrl, fileDir, expectedMD5, offset);
+            allTasks.Add(task);
+            return task;
+        }
+
+        public DownloadTask getDownloadTaskByDownloadTaskId(string taskId) {
+            foreach (DownloadTask down in allTasks) {
+                if (taskId == down.BelongingId) {
+                    return down;
+                }
+            }
+            return null;
+        }
+        public void runAllTasks()
+        {
+            foreach (DownloadTask task in allTasks)
+            {
+                task.resumeTask();
+                factory.StartNew(() => { DownloadTask.download(task); });
+            }
+        }
+
+        public void pauseAllTasks()
+        {
+            foreach (DownloadTask task in allTasks)
+            {
+                task.pauseTask();
+            }
+        }
+        public void resumeAllTasks()
+        {
+            foreach (DownloadTask task in allTasks)
+            {
+                task.resumeTask();
+                factory.StartNew(() => { DownloadTask.download(task); });
+            }
+        }
+
+        public ArrayList getAllTasks() { return allTasks; }
+
+        public Hashtable getAllTasksMap() {
+            Hashtable table = new Hashtable();
+            foreach (DownloadTask down in allTasks) {
+                string belongingid = down.BelongingId;
+                if (table.ContainsKey(belongingid))
+                {
+                    ArrayList arr = (ArrayList)table[belongingid];
+                    arr.Add(down);
+                }
+                else {
+                    ArrayList arr = new ArrayList();
+                    arr.Add(down);
+                    table.Add(belongingid, arr);
+                }
+            }
+            return table;
+        }
+
+        public void runTask(DownloadTask task)
+        {
+            task.resumeTask();
+            factory.StartNew(() => { DownloadTask.download(task); });
+        }
+
+        public void pauseTask(DownloadTask task)
+        {
+            task.pauseTask();
+        }
+        public void resumeTask(DownloadTask task)
+        {
+            task.resumeTask();
+            factory.StartNew(() => { DownloadTask.download(task); });
+        }
+        public void removeTask(DownloadTask task)
+        {
+            task.pauseTask();
+            allTasks.Remove(task);
+        }
+    }
+}

+ 13 - 0
Dispatcher/NettyClient/ClientWrapper.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NettyClient
+{
+    class ClientWrapper
+    {
+        
+    }
+}

+ 139 - 0
Dispatcher/NettyClient/NettyClient.csproj

@@ -0,0 +1,139 @@
+<?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>{7A08D4E8-A171-47BD-A527-BC9BA1833305}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>NettyClient</RootNamespace>
+    <AssemblyName>NettyClient</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\OutputDll\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="DotNetty.Buffers, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\DotNetty.Buffers.0.6.0\lib\net45\DotNetty.Buffers.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Codecs, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\DotNetty.Codecs.0.6.0\lib\net45\DotNetty.Codecs.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Codecs.Protobuf, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\DotNetty.Codecs.Protobuf.0.6.0\lib\net45\DotNetty.Codecs.Protobuf.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Common, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\DotNetty.Common.0.6.0\lib\net45\DotNetty.Common.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Transport, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\DotNetty.Transport.0.6.0\lib\net45\DotNetty.Transport.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Protobuf, Version=3.8.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Google.Protobuf.3.8.0\lib\net45\Google.Protobuf.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Binder, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.Binder.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Logging.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Logging.Abstractions.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Options, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Options.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Options.ConfigurationExtensions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Options.ConfigurationExtensions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Primitives, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Primitives.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.QualityTools.Testing.Fakes, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+    </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.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.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.5.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.Composition" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
+    </Reference>
+    <Reference Include="System.IO.Compression.FileSystem" />
+    <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, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+    </Reference>
+    <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.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ClientWrapper.cs" />
+    <Compile Include="proto\MessageProto.cs" />
+    <Compile Include="proto\MessageUtil.cs" />
+    <Compile Include="TaskNettyClient.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SimpleMessageHandler.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config">
+      <SubType>Designer</SubType>
+    </None>
+    <None Include="packages.config" />
+    <None Include="proto\MessageProto.cs-bak" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 36 - 0
Dispatcher/NettyClient/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("NettyClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("NettyClient")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("7a08d4e8-a171-47bd-a527-bc9ba1833305")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 84 - 0
Dispatcher/NettyClient/SimpleMessageHandler.cs

@@ -0,0 +1,84 @@
+using DotNetty.Transport.Channels;
+using System;
+using System.Collections.Concurrent;
+using System.Windows.Forms;
+using Message = Cn.Sagacloud.Proto.Message;
+
+namespace NettyClient
+{
+    public class SimpleMessageHandler : ChannelHandlerAdapter
+    {
+        public SimpleMessageHandler()
+        {
+
+            //var protobufEncoder = new ProtobufEncoder();
+        }
+        public static ConcurrentQueue<Message> messageQueue = new ConcurrentQueue<Message>();
+        public IChannelHandlerContext context;
+        public override void ChannelActive(IChannelHandlerContext context)
+        {
+            //MessageBox.Show("connected");
+            TaskNettyClient.isConnected = true;
+            this.context = context;
+        }
+        public override void ChannelRead(IChannelHandlerContext context, object message)
+        {
+            if (message is Message msg)
+            {
+                toString(msg);
+                messageQueue.Enqueue(msg);
+            }
+        }
+
+        public override void ChannelReadComplete(IChannelHandlerContext context)
+        {
+            context.Flush();
+        }
+
+        public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
+        {
+            Console.WriteLine("Exception: " + exception);
+            context.CloseAsync();
+        }
+        public override void ChannelInactive(IChannelHandlerContext context)
+        {
+            base.ChannelInactive(context);
+            Console.WriteLine("1");
+            TaskNettyClient.isConnected = false;
+        }
+
+        public override void ChannelUnregistered(IChannelHandlerContext context)
+        {
+            base.ChannelUnregistered(context);
+            Console.WriteLine("2");
+        }
+
+        public override void HandlerRemoved(IChannelHandlerContext context)
+        {
+            base.HandlerRemoved(context);
+        }
+
+
+
+        public void toString(Message msg)
+        {
+            Console.WriteLine("Received from server: cmd : " + msg.Cmd + ", taskId : " + msg.TaskId + ", content : " + msg.Content);
+        }
+        public bool WriteMessage(Message message)
+        {
+            if (context == null || !context.Channel.Active)
+            {
+                return false;
+            }
+            try
+            {
+                context.WriteAndFlushAsync(message);
+            }
+            catch
+            {
+                return false;
+            }
+            return true;
+        }
+    }
+}

+ 111 - 0
Dispatcher/NettyClient/TaskNettyClient.cs

@@ -0,0 +1,111 @@
+using DotNetty.Transport.Bootstrapping;
+using DotNetty.Transport.Channels;
+using DotNetty.Transport.Channels.Sockets;
+using System;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using DotNetty.Codecs.Protobuf;
+using Message = Cn.Sagacloud.Proto.Message;
+
+namespace NettyClient
+{
+    public class TaskNettyClient
+    {
+        private string ip;
+        private int port;
+        IChannel clientChannel;
+        MultithreadEventLoopGroup group;
+        Bootstrap bootstrap;
+        public static bool isConnected = true;
+        public TaskNettyClient(string ip, int port)
+        {
+            this.ip = ip;
+            this.port = port;
+        }
+        public async Task RunClientAsync(ChannelHandlerAdapter channelHandler)
+        {
+            group = new MultithreadEventLoopGroup();
+            try
+            {
+                bootstrap = new Bootstrap();
+                bootstrap
+                    .Group(group)
+                    .Channel<TcpSocketChannel>()
+                    .Option(ChannelOption.TcpNodelay, true)
+                    .Handler(
+                        new ActionChannelInitializer<ISocketChannel>(
+                            channel =>
+                            {
+                                //var protobufEncoder = new ProtobufEncoder();
+                                IChannelPipeline pipeline = channel.Pipeline;
+                                pipeline.AddLast(new ProtobufVarint32LengthFieldPrepender());
+                                pipeline.AddLast(new ProtobufVarint32FrameDecoder());
+                                pipeline.AddLast("encoder", new ProtobufEncoder());
+                                pipeline.AddLast("decoder", new ProtobufDecoder(Message.Parser));
+                                pipeline.AddLast("simple", channelHandler);
+
+                            }));
+                clientChannel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port));
+                //await clientChannel.CloseAsync();
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message + "\r\n" + ex.StackTrace + $"ip:{ip};port{port}");
+            }
+            finally
+            {
+                //await Task.WhenAll(group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)));
+            }
+        }
+        public async Task CloseAsync()
+        {
+            try
+            {
+                await clientChannel.CloseAsync();
+            }
+            catch { }
+            finally
+            {
+                await Task.WhenAll(group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)));
+            }
+        }
+
+        public static void Main(string[] args)
+        {
+            TaskNettyClient client = new TaskNettyClient("47.94.89.44", 6666);
+            SimpleMessageHandler simpleHandler = new SimpleMessageHandler();
+            client.RunClientAsync(simpleHandler).Wait();
+            while (true)
+            {
+                Thread.Sleep(15000);
+                //Console.WriteLine("aaaaaa");
+                client.CloseAsync().Wait();
+                // 重启
+                //client.RunClientAsync(simpleHandler).Wait();
+            }
+        }
+    }
+
+    public static class NettyHelper
+    {
+        //static NettyHelper()
+        //{
+        //    Configuration = new ConfigurationBuilder()
+        //    //    .SetBasePath(ProcessDirectory)
+        //    //    .AddJsonFile("appsettings.json")
+        //        .Build();
+        //}
+
+        //public static IConfigurationRoot Configuration { get; }
+
+        //public static void SetConsoleLogger() => InternalLoggerFactory.DefaultFactory.AddProvider(new ConsoleLoggerProvider((s, level) => true, false));
+        //public static void SetConsoleLogger()
+        //{
+        //    InternalLoggerFactory.DefaultFactory.AddProvider(
+        //        new ConsoleLoggerProvider((s, level) => { level = Microsoft.Extensions.Logging.LogLevel.Error; return true; }, false)
+        //    );
+        //}
+    }
+}

+ 75 - 0
Dispatcher/NettyClient/app.config

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-3.8.0.0" newVersion="3.8.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options.ConfigurationExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Common" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Codecs" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Buffers" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Transport" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>

+ 72 - 0
Dispatcher/NettyClient/packages.config

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="DotNetty.Buffers" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Codecs" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Codecs.Protobuf" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Common" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Transport" version="0.6.0" targetFramework="net461" />
+  <package id="Google.Protobuf" version="3.8.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration.Binder" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Logging" version="1.1.1" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Logging.Abstractions" version="1.1.1" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Options" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Options.ConfigurationExtensions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Primitives" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net461" />
+  <package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="NETStandard.Library" version="1.6.1" targetFramework="net461" />
+  <package id="System.AppContext" version="4.3.0" targetFramework="net461" />
+  <package id="System.Buffers" version="4.4.0" targetFramework="net461" />
+  <package id="System.Collections" version="4.3.0" targetFramework="net461" />
+  <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
+  <package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
+  <package id="System.ComponentModel" version="4.3.0" targetFramework="net461" />
+  <package id="System.ComponentModel.Annotations" version="4.5.0" targetFramework="net461" />
+  <package id="System.Console" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net461" />
+  <package id="System.Globalization" version="4.3.0" targetFramework="net461" />
+  <package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Linq" version="4.3.0" targetFramework="net461" />
+  <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Memory" version="4.5.2" targetFramework="net461" />
+  <package id="System.Net.Http" version="4.3.0" targetFramework="net461" />
+  <package id="System.Net.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Net.Sockets" version="4.3.0" targetFramework="net461" />
+  <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net461" />
+  <package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net461" />
+  <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.Handles" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net461" />
+  <package id="System.Threading.Timer" version="4.3.0" targetFramework="net461" />
+  <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
+  <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
+</packages>

+ 229 - 0
Dispatcher/NettyClient/proto/MessageProto.cs

@@ -0,0 +1,229 @@
+// <auto-generated>
+//     Generated by the protocol buffer compiler.  DO NOT EDIT!
+//     source: MessageProto.proto
+// </auto-generated>
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Cn.Sagacloud.Proto {
+
+  /// <summary>Holder for reflection information generated from MessageProto.proto</summary>
+  public static partial class MessageProtoReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for MessageProto.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static MessageProtoReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "ChJNZXNzYWdlUHJvdG8ucHJvdG8SEmNuLnNhZ2FjbG91ZC5wcm90byI3CgdN",
+            "ZXNzYWdlEgsKA2NtZBgBIAEoCRIOCgZ0YXNrSWQYAiABKAkSDwoHY29udGVu",
+            "dBgDIAEoCUITQg9NZXNzYWdlUHJvdG9TdHJIAWIGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Cn.Sagacloud.Proto.Message), global::Cn.Sagacloud.Proto.Message.Parser, new[]{ "Cmd", "TaskId", "Content" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  public sealed partial class Message : pb::IMessage<Message> {
+    private static readonly pb::MessageParser<Message> _parser = new pb::MessageParser<Message>(() => new Message());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<Message> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Cn.Sagacloud.Proto.MessageProtoReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message(Message other) : this() {
+      cmd_ = other.cmd_;
+      taskId_ = other.taskId_;
+      content_ = other.content_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message Clone() {
+      return new Message(this);
+    }
+
+    /// <summary>Field number for the "cmd" field.</summary>
+    public const int CmdFieldNumber = 1;
+    private string cmd_ = "";
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string Cmd {
+      get { return cmd_; }
+      set {
+        cmd_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "taskId" field.</summary>
+    public const int TaskIdFieldNumber = 2;
+    private string taskId_ = "";
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string TaskId {
+      get { return taskId_; }
+      set {
+        taskId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "content" field.</summary>
+    public const int ContentFieldNumber = 3;
+    private string content_ = "";
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string Content {
+      get { return content_; }
+      set {
+        content_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as Message);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(Message other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Cmd != other.Cmd) return false;
+      if (TaskId != other.TaskId) return false;
+      if (Content != other.Content) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Cmd.Length != 0) hash ^= Cmd.GetHashCode();
+      if (TaskId.Length != 0) hash ^= TaskId.GetHashCode();
+      if (Content.Length != 0) hash ^= Content.GetHashCode();
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Cmd.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Cmd);
+      }
+      if (TaskId.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(TaskId);
+      }
+      if (Content.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(Content);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Cmd.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Cmd);
+      }
+      if (TaskId.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TaskId);
+      }
+      if (Content.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Content);
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(Message other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Cmd.Length != 0) {
+        Cmd = other.Cmd;
+      }
+      if (other.TaskId.Length != 0) {
+        TaskId = other.TaskId;
+      }
+      if (other.Content.Length != 0) {
+        Content = other.Content;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+            break;
+          case 10: {
+            Cmd = input.ReadString();
+            break;
+          }
+          case 18: {
+            TaskId = input.ReadString();
+            break;
+          }
+          case 26: {
+            Content = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code

+ 225 - 0
Dispatcher/NettyClient/proto/MessageProto.cs-bak

@@ -0,0 +1,225 @@
+// <auto-generated>
+//     Generated by the protocol buffer compiler.  DO NOT EDIT!
+//     source: MessageProto.proto
+// </auto-generated>
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = Google.Protobuf;
+using pbr = Google.Protobuf.Reflection;
+namespace NettyClient.proto
+{
+
+    /// <summary>Holder for reflection information generated from MessageProto.proto</summary>
+    public static partial class MessageProtoReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for MessageProto.proto</summary>
+    public static pbr.FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr.FileDescriptor descriptor;
+
+    static MessageProtoReflection() {
+      byte[] descriptorData = System.Convert.FromBase64String(
+          string.Concat(
+            "ChJNZXNzYWdlUHJvdG8ucHJvdG8SEmNuLnNhZ2FjbG91ZC5wcm90byI3CgdN",
+            "ZXNzYWdlEgsKA2NtZBgBIAEoCRIOCgZ0YXNrSWQYAiABKAUSDwoHY29udGVu",
+            "dBgDIAEoCUIQQgxNZXNzYWdlUHJvdG9IAWIGcHJvdG8z"));
+      descriptor = pbr.FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr.FileDescriptor[] { },
+          new pbr.GeneratedClrTypeInfo(null, new pbr.GeneratedClrTypeInfo[] {
+            new pbr.GeneratedClrTypeInfo(typeof(Message), Message.Parser, new[]{ "Cmd", "TaskId", "Content" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  public sealed partial class Message : pb.IMessage<Message> {
+    private static readonly pb.MessageParser<Message> _parser = new pb.MessageParser<Message>(() => new Message());
+     //04 private pb.UnknownFieldSet _unknownFields;
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb.MessageParser<Message> Parser { get { return _parser; } }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr.MessageDescriptor Descriptor {
+      get { return MessageProtoReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr.MessageDescriptor pb.IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message(Message other) : this() {
+      cmd_ = other.cmd_;
+      taskId_ = other.taskId_;
+      content_ = other.content_;
+        //04  _unknownFields = pb.UnknownFieldSet.Clone(other._unknownFields);
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message Clone() {
+      return new Message(this);
+    }
+
+    /// <summary>Field number for the "cmd" field.</summary>
+    public const int CmdFieldNumber = 1;
+    private string cmd_ = "";
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string Cmd {
+      get { return cmd_; }
+      set {
+        cmd_ = pb.ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "taskId" field.</summary>
+    public const int TaskIdFieldNumber = 2;
+    private int taskId_;
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int TaskId {
+      get { return taskId_; }
+      set {
+        taskId_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "content" field.</summary>
+    public const int ContentFieldNumber = 3;
+    private string content_ = "";
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string Content {
+      get { return content_; }
+      set {
+        content_ = pb.ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as Message);
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(Message other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Cmd != other.Cmd) return false;
+      if (TaskId != other.TaskId) return false;
+      if (Content != other.Content) return false;
+        //04  return Equals(_unknownFields, other._unknownFields);
+            return true;
+    }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Cmd.Length != 0) hash ^= Cmd.GetHashCode();
+      if (TaskId != 0) hash ^= TaskId.GetHashCode();
+      if (Content.Length != 0) hash ^= Content.GetHashCode();
+            //04   if (_unknownFields != null) {hash ^= _unknownFields.GetHashCode();}
+            return hash;
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override string ToString() {
+      return pb.JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void WriteTo(pb.CodedOutputStream output) {
+      if (Cmd.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Cmd);
+      }
+      if (TaskId != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(TaskId);
+      }
+      if (Content.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(Content);
+      }
+
+        //04    if (_unknownFields != null){_unknownFields.WriteTo(output);}
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Cmd.Length != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeStringSize(Cmd);
+      }
+      if (TaskId != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeInt32Size(TaskId);
+      }
+      if (Content.Length != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeStringSize(Content);
+      }
+
+            //04    if (_unknownFields != null){size += _unknownFields.CalculateSize();}
+            return size;
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(Message other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Cmd.Length != 0) {
+        Cmd = other.Cmd;
+      }
+      if (other.TaskId != 0) {
+        TaskId = other.TaskId;
+      }
+      if (other.Content.Length != 0) {
+        Content = other.Content;
+      }
+        //04  _unknownFields = pb.UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(pb.CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+              //04 _unknownFields = Google.Protobuf.UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+                        break;
+          case 10: {
+            Cmd = input.ReadString();
+            break;
+          }
+          case 16: {
+            TaskId = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            Content = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code

+ 29 - 0
Dispatcher/NettyClient/proto/MessageUtil.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Message = Cn.Sagacloud.Proto.Message;
+
+namespace NettyClient.proto
+{
+    public class MessageUtil
+    {
+        //public static Message generateMessage(string cmd, int taskId, string content) {
+        //    Message msg = new Message();
+        //    msg.Cmd = cmd;
+        //    msg.TaskId = taskId;
+        //    msg.Content = content;
+        //    return msg;
+        //}
+
+        public static Message generateMessageStr(string cmd, string taskId, string content)
+        {
+            Message msg = new Message();
+            msg.Cmd = cmd;
+            msg.TaskId = taskId;
+            msg.Content = content;
+            return msg;
+        }
+    }
+}

+ 79 - 0
Dispatcher/ServiceMBI.sln

@@ -0,0 +1,79 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.3
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpDownload", "HttpDownload\HttpDownload.csproj", "{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NettyClient", "NettyClient\NettyClient.csproj", "{7A08D4E8-A171-47BD-A527-BC9BA1833305}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskDatabase", "TaskDatabase\TaskDatabase.csproj", "{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|x64.Build.0 = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|x86.Build.0 = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|x64.ActiveCfg = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|x64.Build.0 = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|x86.ActiveCfg = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|x86.Build.0 = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|x64.Build.0 = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|x86.Build.0 = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|x64.ActiveCfg = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|x64.Build.0 = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|x86.ActiveCfg = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|x86.Build.0 = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|x64.Build.0 = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|x86.Build.0 = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|x64.ActiveCfg = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|x64.Build.0 = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|x86.ActiveCfg = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|x86.Build.0 = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|x64.Build.0 = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|x86.Build.0 = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|x64.ActiveCfg = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|x64.Build.0 = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|x86.ActiveCfg = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {EF8DCEE9-4A1C-4EFD-A378-13ABCBBBA018}
+	EndGlobalSection
+EndGlobal

BIN
Dispatcher/TaskDatabase/FakesAssemblies/Remotion.Linq.Fakes.dll


BIN
Dispatcher/TaskDatabase/FakesAssemblies/Remotion.Linq.Fakes.fakesconfig


+ 258 - 0
Dispatcher/TaskDatabase/FakesAssemblies/Remotion.Linq.Fakes.messages

@@ -0,0 +1,258 @@
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.AssertionConditionAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.AssertionConditionType 生成存根: 类型是一个值类型。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.AssertionMethodAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.BaseTypeRequiredAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.CanBeNullAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.CannotApplyEqualityOperatorAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.ContractAnnotationAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.ImplicitUseKindFlags 生成存根: 类型是一个值类型。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.ImplicitUseTargetFlags 生成存根: 类型是一个值类型。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.InstantHandleAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.InvokerParameterNameAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.LinqTunnelAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.LocalizationRequiredAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.MeansImplicitUseAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.NoEnumerationAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.NotifyPropertyChangedInvocatorAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.NotNullAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.PathReferenceAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.PublicAPIAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.PureAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.StringFormatMethodAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.TerminatesProgramAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.UsedImplicitlyAttribute 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Utilities.ArgumentUtility 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Utilities.Assertion 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Utilities.NullableTypeUtility 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.FromClauseBase 生成存根: 类型没有系列可见的构造函数。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.AdditionalFromClause 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.CloneContext 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.Expressions.PartialEvaluationExceptionExpression 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.Expressions.QuerySourceReferenceExpression 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.Expressions.SubQueryExpression 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.Expressions.VBStringComparisonExpression 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ExpressionVisitors.AccessorFindingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ExpressionVisitors.CloningExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ExpressionVisitors.ReferenceReplacingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ExpressionVisitors.ReverseResolvingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.GroupJoinClause 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.JoinClause 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.MainFromClause 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.OrderByClause 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.Ordering 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.OrderingDirection 生成存根: 类型是一个值类型。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.QuerySourceMapping 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.AggregateFromSeedResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.AggregateResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.AllResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.AnyResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.AsQueryableResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.AverageResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.CastResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.ConcatResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.ContainsResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.CountResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.DefaultIfEmptyResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.DistinctResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.ExceptResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.FirstResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.GroupResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.IntersectResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.LastResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.LongCountResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.MaxResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.MinResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.OfTypeResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.ReverseResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.SingleResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.SkipResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.SumResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.TakeResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.UnionResultOperator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.SelectClause 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.StreamedData.StreamedValueInfo 生成存根: 类型没有系列可见的构造函数。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.StreamedData.StreamedScalarValueInfo 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.StreamedData.StreamedSequence 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.StreamedData.StreamedSequenceInfo 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.StreamedData.StreamedSingleValueInfo 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.StreamedData.StreamedValue 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.WhereClause 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Collections.ChangeResistantObservableCollectionEnumerator`1 生成存根: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Collections.IndexValuePair`1 生成存根: 类型是一个值类型。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Collections.MultiDictionaryExtensions 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Collections.ObservableCollectionExtensions 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.QueryProviderBase 生成存根: 类型包含会导致编译错误的过时成员。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.DefaultQueryProvider 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.MultiReplacingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.PartialEvaluatingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.ReplacingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.SubQueryFindingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.Transformation.ExpressionTransformation 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.TransformingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.TransparentIdentifierRemovingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.TreeEvaluation.EvaluatableTreeFindingExpressionVisitor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.TreeEvaluation.NullEvaluatableExpressionFilter 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ParserException 生成存根: 类型没有系列可见的构造函数。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.ExpressionTreeParser 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.ExpressionTreeProcessors.CompoundExpressionTreeProcessor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.ExpressionTreeProcessors.NullExpressionTreeProcessor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.ExpressionTreeProcessors.PartialEvaluatingExpressionTreeProcessor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.ExpressionTreeProcessors.TransformingExpressionTreeProcessor 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AggregateExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AggregateFromSeedExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AllExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AnyExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AsQueryableExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AverageExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.CastExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ClauseGenerationContext 生成存根: 类型是一个值类型。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ConcatExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ContainsExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.CountExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.DefaultIfEmptyExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.DistinctExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ExceptExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ExpressionNodeInstantiationException 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ExpressionResolver 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.FirstExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.GroupByExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.GroupByWithResultSelectorExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.GroupJoinExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.IntersectExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.JoinExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.LastExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.LongCountExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.MainSourceExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.MaxExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.MethodCallExpressionNodeFactory 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.MethodCallExpressionParseInfo 生成存根: 类型是一个值类型。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.MinExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.OfTypeExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.OrderByDescendingExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.OrderByExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.QuerySourceExpressionNodeUtility 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ResolvedExpressionCache`1 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ReverseExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SelectExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SelectManyExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SingleExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SkipExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SumExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SupportedMethodSpecifications 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.TakeExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ThenByDescendingExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ThenByExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.UnionExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.WhereExpressionNode 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.MethodCallExpressionParser 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.CompoundNodeTypeProvider 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.MethodInfoBasedNodeTypeRegistry 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.MethodNameBasedNodeTypeRegistry 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.NameBasedRegistrationInfo 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.QueryParser 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.TupleExpressionBuilder 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.QueryModel 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.QueryModelBuilder 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.UniqueIdentifierGenerator 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Utilities.ExpressionExtensions 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Utilities.ItemTypeReflectionUtility 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 System.Reflection.ReflectionExtensions 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Utilities.ReflectionUtility 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Utilities.StringUtility 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 <>f__AnonymousType0`2 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 <>f__AnonymousType1`3 生成存根: 类型已密封。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.AssertionConditionAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.AssertionConditionType 生成填充码: 类型是一个枚举。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.AssertionMethodAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.BaseTypeRequiredAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.CanBeNullAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.CannotApplyEqualityOperatorAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.ContractAnnotationAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.ImplicitUseKindFlags 生成填充码: 类型是一个枚举。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.ImplicitUseTargetFlags 生成填充码: 类型是一个枚举。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.InstantHandleAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.InvokerParameterNameAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.LinqTunnelAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.LocalizationRequiredAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.MeansImplicitUseAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.NoEnumerationAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.NotifyPropertyChangedInvocatorAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.NotNullAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.PathReferenceAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.PublicAPIAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.PureAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.StringFormatMethodAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.TerminatesProgramAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 JetBrains.Annotations.UsedImplicitlyAttribute 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Utilities.ArgumentUtility 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Utilities.Assertion 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Utilities.NullableTypeUtility 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.IClause 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.IQuerySource 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.IFromClause 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.IBodyClause 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.Expressions.IPartialEvaluationExceptionExpressionVisitor 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.Expressions.IVBSpecificExpressionVisitor 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.RelinqExpressionVisitor+<AdjustArgumentsForNewExpression>d__0 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.OrderingDirection 生成填充码: 类型是一个枚举。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.ResultOperators.AsQueryableResultOperator+ISupportedByIQueryModelVistor 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.StreamedData.IStreamedData 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Clauses.StreamedData.IStreamedDataInfo 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Collections.ChangeResistantObservableCollectionEnumerator`1 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Collections.IndexValuePair`1 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Collections.MultiDictionaryExtensions 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Collections.ObservableCollectionExtensions 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.IQueryExecutor 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.IQueryModelVisitor 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.Transformation.ExpressionTransformation 生成填充码: 类型是一个委托。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.Transformation.IExpressionTranformationProvider 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.Transformation.ExpressionTransformerRegistry+<>c__DisplayClass1`1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.Transformation.IExpressionTransformer`1 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.Transformation.PredefinedTransformations.AttributeEvaluatingExpressionTransformer+IMethodCallExpressionTransformerAttribute 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.Transformation.PredefinedTransformations.TupleNewExpressionTransformer+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.TransparentIdentifierRemovingExpressionVisitor+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.TransparentIdentifierRemovingExpressionVisitor+<GetMemberBindingsForNewExpression>d__7 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.TreeEvaluation.IEvaluatableExpressionFilter 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ExpressionVisitors.TreeEvaluation.NullEvaluatableExpressionFilter 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.ParserException 生成填充码: 类型已过时。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IExpressionTreeProcessor 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.INodeTypeProvider 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.IExpressionNode 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AggregateExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AggregateFromSeedExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.AllExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.IQuerySourceExpressionNode 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ContainsExpressionNode+<GetSupportedMethodNames>d__2 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.CountExpressionNode+<GetSupportedMethods>d__0 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.GroupByExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.GroupByExpressionNode+<>c__DisplayClass4 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.GroupJoinExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.JoinExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.JoinExpressionNode+<>c__DisplayClass4 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.JoinExpressionNode+<>c__DisplayClass7 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.LongCountExpressionNode+<GetSupportedMethods>d__0 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.OrderByDescendingExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.OrderByExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SelectExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SelectManyExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SelectManyExpressionNode+<>c__DisplayClass4 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.SupportedMethodSpecifications 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ThenByDescendingExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.ThenByExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IntermediateModel.WhereExpressionNode+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.IQueryParser 生成填充码: 类型是一个接口。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.CompoundNodeTypeProvider+<>c__DisplayClass1 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.CompoundNodeTypeProvider+<>c__DisplayClass6 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.MethodInfoBasedNodeTypeRegistry+<>c__DisplayClass10 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.MethodInfoBasedNodeTypeRegistry+<>c__DisplayClass16 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.MethodInfoBasedNodeTypeRegistry+<>c__DisplayClass3 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.Structure.NodeTypeProviders.MethodNameBasedNodeTypeRegistry+<>c__DisplayClass3 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Parsing.TupleExpressionBuilder+<GetExpressionsFromTuple>d__2 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.QueryModel+CloningExpressionVisitor 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Transformations.SubQueryFromClauseFlattener+<>c__DisplayClass2 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Utilities.ExpressionExtensions 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 System.Reflection.ReflectionExtensions 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Utilities.ReflectionUtility 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 Remotion.Linq.Utilities.StringUtility 生成填充码: 类型对 exported or assembly(Remotion.Linq.Fakes) 不可见。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 <>f__AnonymousType0`2 生成填充码: 类型不受支持,因为存在内部限制。
+D:\Saga\ServiceRevit\Dispatcher\TaskDatabase\Fakes\Remotion.Linq.fakes : warning : 无法为 <>f__AnonymousType1`3 生成填充码: 类型不受支持,因为存在内部限制。

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 11450 - 0
Dispatcher/TaskDatabase/FakesAssemblies/Remotion.Linq.Fakes.xml


+ 41 - 0
Dispatcher/TaskDatabase/Mappings/TaskModel.hbm.xml

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+                   assembly="TaskDatabase" default-lazy="false"
+                   namespace="TaskDatabase.Model">
+
+  <!-- more mapping info here -->
+  <class name="TaskModel" table="task" entity-name="TaskModel">
+    <id name="Tid">
+      <!--<generator class="guid" />-->
+      <generator class="identity" />
+      <!--  <generator class="native" />主键自增。使用数据库自带的生成器 -->
+    </id>
+    <property name="Id" column="id" type="string"/>
+    <property name="Task_name"/>
+    <property name="Task_cmd" update="false" />
+    <property name="Task_param" update="false"/>
+    <property name="Task_status"/>
+    <property name="Task_result_json" />
+    <property name="Task_expected_finish_time"  update="false"/>
+    <property name="Task_add_time" insert="false" update="false"/>
+    <set name="DownloadTaskModelList">
+      <key column="Task_id" property-ref="Id"/>
+      <one-to-many class="DownloadTaskModel"/>
+    </set>
+  </class>
+
+  <class name="DownloadTaskModel" table="download">
+    <id name="Id" column="id">
+      <!--<generator class="guid" />-->
+      <generator class="identity" />
+      <!--  <generator class="native" />主键自增。使用数据库自带的生成器 -->
+    </id>
+    <property name="Task_id" />
+    <property name="Task_url" />
+    <property name="Task_md5" />
+    <property name="Local_dir" />
+    <property name="Downloaded_bytes" />
+    <property name="File_bytes" />
+    <property name="Finish_time" />
+  </class>
+</hibernate-mapping>

+ 22 - 0
Dispatcher/TaskDatabase/Model/DownloadTaskModel.cs

@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+
+namespace TaskDatabase.Model
+{
+
+    public class DownloadTaskModel
+    {
+        //public virtual int Tid { get; set; }
+        //[JsonProperty(PropertyName = "id")]
+        public virtual int Id { get; set; }
+        [JsonProperty(PropertyName = "taskId")]
+        public virtual string Task_id { get; set; }
+        [JsonProperty(PropertyName = "httpUrl")]
+        public virtual string Task_url { get; set; }
+        [JsonProperty(PropertyName = "md5")]
+        public virtual string Task_md5 { get; set; }
+        public virtual string Local_dir { get; set; }
+        public virtual long Downloaded_bytes { get; set; }
+        public virtual long File_bytes { get; set; }
+        public virtual long Finish_time { get; set; }
+    }
+}

+ 32 - 0
Dispatcher/TaskDatabase/Model/TaskModel.cs

@@ -0,0 +1,32 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TaskDatabase.Model
+{
+    public class TaskModel
+    {
+        public virtual int Tid { get; set; }
+        [JsonProperty(PropertyName = "id")]
+        public virtual string Id { get; set; }
+        [JsonProperty(PropertyName = "name")]
+        public virtual string Task_name { get; set; }
+        [JsonProperty(PropertyName = "cmd")]
+        public virtual string Task_cmd { get; set; }
+        [JsonProperty(PropertyName = "param")]
+        public virtual string Task_param { get; set; }
+        [JsonProperty(PropertyName = "status")]
+        public virtual int Task_status { get; set; }
+        [JsonProperty(PropertyName = "resultJson")]
+        public virtual string Task_result_json { get; set; }
+        [JsonProperty(PropertyName = "expectedFinishTime")]
+        public virtual long Task_expected_finish_time { get; set; }
+        public virtual DateTime Task_add_time { get; set; }
+        [JsonProperty(PropertyName = "downloadTaskList")]
+        public virtual ICollection<DownloadTaskModel> DownloadTaskModelList { get; set; }
+    }
+    
+}

+ 42 - 0
Dispatcher/TaskDatabase/NHibernateHelper.cs

@@ -0,0 +1,42 @@
+using NHibernate;
+using NHibernate.Cfg;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TaskDatabase
+{
+    public class NHibernateHelper
+    {
+        private static object lockObj = new object();
+        private static ISessionFactory _sessionFactory;
+
+        private static ISessionFactory SessionFactory
+        {
+            get
+            {
+                if (_sessionFactory == null)
+                {
+                    lock (lockObj)
+                    {
+                        if (_sessionFactory == null)
+                        {
+                            var configuration = new Configuration();
+                            configuration.Configure();
+                            //configuration.AddAssembly(typeof(TaskModel).Assembly);
+                            _sessionFactory = configuration.BuildSessionFactory();
+                        }
+                    }
+                }
+                return _sessionFactory;
+            }
+        }
+
+        public static ISession OpenSession()
+        {
+            return SessionFactory.OpenSession();
+        }
+    }
+}

+ 36 - 0
Dispatcher/TaskDatabase/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("TaskDatabase")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("TaskDatabase")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("ade36aa5-fca8-4e5b-a27e-2360884404b3")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 95 - 0
Dispatcher/TaskDatabase/TaskDatabase.csproj

@@ -0,0 +1,95 @@
+<?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>{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>TaskDatabase</RootNamespace>
+    <AssemblyName>TaskDatabase</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\OutputDll\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Antlr3.Runtime, Version=3.5.0.2, Culture=neutral, PublicKeyToken=eb42632606e9261f, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll</HintPath>
+    </Reference>
+    <Reference Include="Iesi.Collections, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.QualityTools.Testing.Fakes, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Newtonsoft.Json.11.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="NHibernate, Version=5.2.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\NHibernate.5.2.7\lib\net461\NHibernate.dll</HintPath>
+    </Reference>
+    <Reference Include="Remotion.Linq, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll</HintPath>
+    </Reference>
+    <Reference Include="Remotion.Linq.EagerFetching, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
+      <HintPath>..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.ComponentModel" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Configuration.Install" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Drawing.Design" />
+    <Reference Include="System.Management" />
+    <Reference Include="System.ServiceModel" />
+    <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="Model\TaskModel.cs" />
+    <Compile Include="NHibernateHelper.cs" />
+    <Compile Include="Model\DownloadTaskModel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TaskService.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Mappings\TaskModel.hbm.xml">
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="hibernate.cfg.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+      <SubType>Designer</SubType>
+    </Content>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 214 - 0
Dispatcher/TaskDatabase/TaskService.cs

@@ -0,0 +1,214 @@
+using NHibernate;
+using NHibernate.Criterion;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TaskDatabase.Model;
+
+namespace TaskDatabase
+{
+    public class TaskService
+    {
+        public bool AddTask(TaskModel task) {
+            ITransaction transaction = null;
+            try
+            {
+                //如果存在该任务, 则不允许添加
+                if (isContainsTask(task.Id))
+                {
+                    return false;
+                }
+                using (ISession session = NHibernateHelper.OpenSession()) {
+                    using (transaction = session.BeginTransaction()) {
+                        try
+                        {
+                            session.Save(task);
+                            if (task.DownloadTaskModelList != null)
+                            {
+                                foreach(var download in task.DownloadTaskModelList)
+                                {
+                                    session.Save(download);
+                                }
+                            }
+                            transaction.Commit();
+                        }
+                        catch (Exception ex){
+                            Console.WriteLine("write:" + ex.Message);
+                            if (transaction != null && transaction.IsActive)
+                            {
+                                transaction.Rollback();
+                            }
+                        }
+                    }
+                }
+                return true;
+            }
+            catch {}
+            return false;
+        }
+
+        public bool UpdateTask(TaskModel task)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        session.Update(task);
+                        transaction.Commit();
+                    }
+                }
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message+ex.StackTrace);
+            }
+            return false;
+        }
+        public bool UpdateDownload(DownloadTaskModel download)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        session.Update(download);
+                        transaction.Commit();
+                    }
+                }
+                return true;
+            }
+            catch { }
+            return false;
+        }
+        public IList<TaskModel> GetTasksByStatus(int status)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Eq("Task_status", status))
+                                .List<TaskModel>();
+                        return queryResult;
+                    }
+                }
+            }
+            catch (Exception ex){
+                
+                Console.WriteLine(ex.Message);
+            }
+            return null;
+        }
+
+        public TaskModel GetTasksByTid(string taskId)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Eq("Id", taskId))
+                                .UniqueResult<TaskModel>();
+                        return queryResult;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+
+                Console.WriteLine(ex.Message);
+            }
+            return null;
+        }
+
+        public IList<TaskModel> GetTasksByTaskId(string taskId)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Eq("Id", taskId))
+                                .List<TaskModel>();
+                        return queryResult;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+            return null;
+        }
+
+        public bool isContainsTask(string taskId)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Eq("Id", taskId))
+                                .List<TaskModel>();
+                        return queryResult.Count > 0;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+            return true;
+        }
+
+        public void removeErrorTask()
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Le("Task_status", -1))
+                                .List<TaskModel>();
+                        for (int i = 0; i < queryResult.Count; ++i) {
+                            ICollection<DownloadTaskModel> downloadTaskModels = queryResult[i].DownloadTaskModelList;
+                            for (int j = 0; j < downloadTaskModels.Count; ++j) {
+                                session.Delete(downloadTaskModels.ElementAt(j));
+                            }
+                            session.Delete(queryResult[i]);
+                        }
+                        transaction.Commit();
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+        }
+    }
+}

+ 11 - 0
Dispatcher/TaskDatabase/hibernate.cfg.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
+  <session-factory>
+    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
+    <property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
+    <property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
+    <property name="connection.connection_string">Server=127.0.0.1;Database=worker_str;User ID=root;Password=123456</property>
+    <property name="show_sql">false</property>
+    <mapping assembly="TaskDatabase"/>
+  </session-factory>
+</hibernate-configuration>

+ 9 - 0
Dispatcher/TaskDatabase/packages.config

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Antlr3.Runtime" version="3.5.1" targetFramework="net461" />
+  <package id="Iesi.Collections" version="4.0.4" targetFramework="net461" />
+  <package id="Newtonsoft.Json" version="11.0.1" targetFramework="net461" />
+  <package id="NHibernate" version="5.2.7" targetFramework="net461" />
+  <package id="Remotion.Linq" version="2.2.0" targetFramework="net461" />
+  <package id="Remotion.Linq.EagerFetching" version="2.2.0" targetFramework="net461" />
+</packages>

+ 85 - 0
Executer/DataCheck/CheckFactory.cs

@@ -0,0 +1,85 @@
+/* ==============================================================================
+ * 功能描述:CheckFactory  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:26:56
+ * ==============================================================================*/
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using ServiceRevitLib.Mode;
+using Autodesk.Revit.DB;
+using ServiceRevitLib.DataCheck.Mode;
+using ServiceRevitLib.Extend;
+
+namespace ServiceRevitLib
+{
+    /// <summary>
+    /// CheckFactory
+    /// </summary>
+    public class CheckFactory:ResultBase
+    {
+        public CheckFactory()
+        {
+            Content=new List<CheckBase>();
+        }
+
+      
+
+        #region 序列化的属性
+
+        public List<CheckBase> Content { get; set; }
+
+        public string FloorName { get; set; }
+
+        #endregion
+
+        #region Method
+        /// <summary>
+        /// 由传入字符串获取检查项
+        /// 传入的检查列表使用“,”进行分割
+        /// </summary>
+        /// <param name="checkItemStrs"></param>
+        public void SetCheckItems(string str)
+        {
+            //SagaCheck,UnitCheck,FamilyNameCheck,EquipPartLocationCheck,ColumnCheck,ElementRangeCheck,ConnectorCheck,SystemNameCheck,EquipInSpaceCheck,SystemReferEquipCheck,ParameterIntegrityCheck,PipeCheck,XYZOverlapCheck
+            var checkItemStrs = str.Split(',');
+            var nameSpace = typeof(CheckBase).Namespace;
+            foreach (string itemStr in checkItemStrs)
+            {
+                //子类与父类应该使用同一命名空间;如果为Program+BaseClass格式,会出错; 如果出现此情况,请更改方法
+                string fullPath = nameSpace + "." + itemStr;
+                Assembly tempAsembly = Assembly.GetExecutingAssembly();
+                var check = (tempAsembly.CreateInstance(fullPath)) as CheckBase;
+
+                Content.Add(check);
+            }
+        }
+
+        public void Check(Document doc)
+        {
+            FloorName = doc.PathName;
+            //Document doc = DocumentUtils.GetDocument(path);
+            try
+            {
+                Content.ForEach(t => t.SetDoc(doc));
+                Content.ForEach(t => t.Check());
+            }
+            catch (Exception e)
+            {
+                ResultMsg = e.Message;
+                Result = ResultState.Failure;
+            }
+            finally
+            {
+                //doc.CloseExt();
+            }
+        }
+
+        #endregion
+
+    }
+}

+ 40 - 0
Executer/DataCheck/Common/MBIConst.cs

@@ -0,0 +1,40 @@
+/* ==============================================================================
+ * 功能描述:MBIConst  
+ * 创 建 者:Garrett
+ * 创建日期:2018/3/13 19:31:08
+ * ==============================================================================*/
+
+using System;
+using System.IO;
+using SAGA.DotNetUtils;
+
+namespace ServiceRevitLib.Common
+{
+    /// <summary>
+    /// MBIConst
+    /// </summary>
+    public class MBIConst
+    {
+        
+        public static readonly string MBIResourcePath = Path.Combine(AppBaseInfo.DllRunPath, "MBIResource");
+
+        /// <summary>
+        /// 设备本地编码
+        /// </summary>
+        public readonly static string EquipLocalID = "设备本地编码";
+        /// <summary>
+        /// 设备本地名称
+        /// </summary>
+        public readonly static string EquipLocalName = "设备本地名称";
+
+        /// <summary>
+        /// 立管开始标志[start]
+        /// </summary>
+        public static string StartFlag { get; private set; } = "start";
+
+        //最少空间的面积. 0.4m  削减因子: 1
+        public static readonly double SpacePerimeterTolerance = Math.Pow(0.4 * 1000 / 304.8, 2) / 100;
+        //最小空间的周长. 0.4m  削减因子: 1
+        public static readonly double SpaceAreaTolerance = (0.4 * 1000 / 304.8 * 4) / 100;
+    }
+}

+ 46 - 0
Executer/DataCheck/Common/RegexConstPattern.cs

@@ -0,0 +1,46 @@
+/* ==============================================================================
+ * 功能描述:RegexPatten  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/29 14:12:17
+ * ==============================================================================*/
+
+using NPOI.OpenXml4Net.OPC;
+using System.Configuration;
+
+namespace ServiceRevitLib.Common
+{
+    /// <summary>
+    /// RegexPatten
+    /// </summary>
+    public static class RegexConstPattern
+    {
+        static RegexConstPattern()
+        {
+            SagaSign = ConfigurationManager.AppSettings["SagaSign"];
+            IsMBIView = @"^([BF]\d*M?\d?|RFM?\d?)" + SagaSign + @"$";
+            IsRF = @"^RF(" + SagaSign + ")?$";
+        }
+        public static readonly string SagaSign;
+        public const string IsSpaceId = @"^Si\S*";
+        public const string IsEquipId = @"^Eq\S*";
+        public const string IsEquipPartId = @"^Ec\S*";
+        public const string IsBeaconId = @"^VOBc\S*";
+
+
+        public const string IsEquip = @"^[A-Z]{4}\s*-\s*\S*";
+        public const string IsEquipPart = @"^[A-Z]{6}\s*-\s*\S*";
+        public const string IsBeacon = @"^Beacon$";
+
+        public const string IsMBILevel = @"^([BF][1-9]\d*M?\d?|RFM?\d?)$";
+        public static readonly string IsMBIView;
+        public const string IsSandwich = @"^([BF][1-9]\d*M\d?|RFM\d?)$";
+
+        public static readonly string IsRF;
+        public const string IsRFM = @"^RFM\d*$";
+        public const string IsOnground = @"^F\s*";
+        public const string IsUnderground = @"^B\s*";
+
+        public const string IsPhoneNumber = @"^1[3|4|5|7|8][0-9]\d{8}$";
+
+    }
+}

+ 59 - 0
Executer/DataCheck/DataCheck.Mode/CheckBase.cs

@@ -0,0 +1,59 @@
+/* ==============================================================================
+ * 功能描述:CheckBase  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:01:26
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using Autodesk.Revit.DB;
+using Newtonsoft.Json;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// CheckBase
+    /// </summary>
+    public class CheckBase:ResultBase
+    {
+        public CheckBase()
+        {
+            Content=new List<ResultBase>();
+        }
+        private string m_Name;
+        /// <summary>
+        /// 检查项名称
+        /// </summary>
+        public string Name
+        {
+            get { return this.GetType().Name; }
+        }
+
+
+        public List<ResultBase> Content { get; set; }
+        /// <summary>
+        /// 关联表的名称
+        /// </summary>
+        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+        public string ReferenceSheet { get; set; }
+
+
+        #region Method
+        
+        protected Document m_Doc { get; set; }
+
+        public void SetDoc(Document doc)
+        {
+            m_Doc = doc;
+        }
+        public virtual void Check()
+        {
+            if(m_Doc==null)throw new NullReferenceException();
+
+            Console.WriteLine(this.Name + "Checked");
+        }
+
+        #endregion
+    }
+}

+ 56 - 0
Executer/DataCheck/DataCheck.Mode/ColumnCheck.cs

@@ -0,0 +1,56 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using Autodesk.Revit.DB;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class ColumnCheck : CheckBase
+    {
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                var document = m_Doc;
+                var elements = document.GetElements<FamilyInstance>(BuiltInCategory.OST_StructuralColumns);
+                foreach (FamilyInstance fi in elements)
+                {
+                    var result = new ColumnCheckResult();
+                    result.FamilyName = fi.GetFamilyName();
+                    result.Id = fi.Id.ToString();
+                    var roomBoundaries = fi.GetParameterInteger(BuiltInParameter.WALL_ATTR_ROOM_BOUNDING);
+                    if (roomBoundaries == 1)
+                    {
+                        result.Result = ResultState.Success;
+                    }
+                    else
+                    {
+                        result.Result = ResultState.Failure;
+                        result.ResultMsg = "柱的房间边界属性 未勾选";
+                    }
+                    Content.Add(result);
+                }
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+        }
+    }
+}

+ 26 - 0
Executer/DataCheck/DataCheck.Mode/ColumnCheckResult.cs

@@ -0,0 +1,26 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class ColumnCheckResult : ResultBase
+    {
+        /// <summary>
+        /// id
+        /// </summary>
+        public string Id { get; set; }
+        /// <summary>
+        /// 族名称
+        /// </summary>
+        public string FamilyName { get; set; }
+        
+    }
+}

+ 168 - 0
Executer/DataCheck/DataCheck.Mode/ConnectorCheck.cs

@@ -0,0 +1,168 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Autodesk.Revit.DB;
+using SAGA.DotNetUtils.Extend;
+using SAGA.RevitUtils.MEP;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+using ServiceRevitLib.Utils;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class ConnectorCheck : CheckBase
+    {
+        public ConnectorCheck()
+        {
+            ReferenceSheet = "参考-连接件对照表";
+        }
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                bool unitResult = true;
+                m_ProDefineConnectors = GetPreDefineConnectors();
+                var elements = m_Doc.GetEqEcElements();
+
+                foreach (var element in elements)
+                {
+                    //检查设备或者部件
+                    var result = GetCheckResult(element);
+                    if (result == null) continue;
+                    Content.Add(result);
+                }
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+        }
+        
+
+        private string m_HaveConnectorSing = "√";
+        private List<DCR_Connector> m_ProDefineConnectors;
+
+        public List<DCR_Connector> GetPreDefineConnectors()
+        {
+            var list = new List<DCR_Connector>();
+            var alllist = DataCheckRule.GetPreDefineConnectors();
+            foreach (DCR_Connector connector in alllist)
+            {
+                var pipeType = connector.PipeConnector;
+                var hvacType = connector.HvacConnector;
+                if (pipeType == m_HaveConnectorSing || hvacType == m_HaveConnectorSing)
+                {
+                    list.Add(connector);
+                    if (connector.PName.IsNotNullEmpty() && connector.PCode.IsNotNullEmpty())
+                    {
+                        //部件单独提出来当做一项
+                        var pconnector = new DCR_Connector()
+                        {
+                            Code = connector.PCode,
+                            Name = connector.Name,
+                            PipeConnector = connector.PipeConnector,
+                            HvacConnector = connector.HvacConnector
+                        };
+                        list.Add(pconnector);
+                    }
+                }
+            }
+            return list;
+        }
+        /// <summary>
+        /// 获取检测结果
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        private ConnectorCheckResult GetCheckResult(Element element)
+        {
+            if (element == null) return null;
+            var result = new ConnectorCheckResult();
+            var code = element.GetFamilyCode();
+            var defineConType = GetDefineConType(code);
+            if (defineConType == null) return null;
+            var type= code.Length == 4 ? ElementRangeCheck.DCElementType.Equipment : ElementRangeCheck.DCElementType.EuipmentPart;
+            result.Type = type.GetDescription();
+            result.FamilyName = element.GetFamilyName();
+            result.Id = element.Id.ToString();
+            result.Result = ResultState.Success;
+            CheckConType(result, element, defineConType.Item1);
+            CheckConType(result, element, defineConType.Item2);
+            return result;
+        }
+        /// <summary>
+        /// 获取定义的风和水连接件类型
+        /// </summary>
+        /// <param name="code"></param>
+        /// <returns></returns>
+        private Tuple<Domain, Domain> GetDefineConType(string code)
+        {
+            var item = m_ProDefineConnectors.FirstOrDefault(t => t.Code == code);
+            if (item == null) return null;
+            var pipeType = item.PipeConnector;
+            var hvacType = item.HvacConnector;
+
+            var pipeConType = pipeType == m_HaveConnectorSing ? Domain.DomainPiping : Domain.DomainUndefined;
+            var hvacConType = hvacType == m_HaveConnectorSing ? Domain.DomainHvac : Domain.DomainUndefined;
+            return new Tuple<Domain, Domain>(pipeConType, hvacConType);
+        }
+        /// <summary>
+        /// 检查连接件类型是否存在
+        /// </summary>
+        /// <param name="result"></param>
+        /// <param name="domain"></param>
+        private void CheckConType(ConnectorCheckResult result, Element fi, Domain domain)
+        {
+            if (domain != Domain.DomainUndefined)
+            {
+                var connectors = fi.GetConnectors(domain);
+                var domainStr = DomainToString(domain);
+                if (connectors.Any())
+                {
+                    if (connectors.All(t => t.IsConnected)) return;
+                    result.Result = ResultState.Failure;
+                    result.ResultMsg += $"发现 {domainStr}连接件未连接;";
+                }
+                else
+                {
+                    result.Result = ResultState.Failure;
+                    result.ResultMsg += $"缺少 {domainStr} 连接件;";
+                }
+            }
+        }
+
+        private string DomainToString(Domain domain)
+        {
+            string str = "";
+            switch (domain)
+            {
+                case Domain.DomainPiping:
+                    str = "水管";
+                    break;
+                case Domain.DomainHvac:
+                    str = "风管";
+                    break;
+                default:
+                    str = "未知";
+                    break;
+
+            }
+            return str;
+        }
+    }
+}

+ 30 - 0
Executer/DataCheck/DataCheck.Mode/ConnectorCheckResult.cs

@@ -0,0 +1,30 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class ConnectorCheckResult : ResultBase
+    {
+        /// <summary>
+        /// id
+        /// </summary>
+        public string Id { get; set; }
+        /// <summary>
+        /// 族名称
+        /// </summary>
+        public string FamilyName { get; set; }
+
+        /// <summary>
+        /// 构件类型
+        /// </summary>
+        public string Type { get; set; }
+    }
+}

+ 268 - 0
Executer/DataCheck/DataCheck.Mode/ElementRangeCheck.cs

@@ -0,0 +1,268 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using SAGA.DotNetUtils.Extend;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Common;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class ElementRangeCheck : CheckBase
+    {
+        #region 序列化属性
+        private double m_Redundant = 500;
+        /// <summary>
+        /// 高度冗余
+        /// </summary>
+        public double Redundant
+        {
+            get { return m_Redundant; }
+            set { m_Redundant = value; }
+        }
+
+
+        private double m_baseLevel;
+        /// <summary>
+        /// 底部标高
+        /// </summary>
+        public double BaseLevel
+        {
+            get { return m_baseLevel; }
+        }
+
+        private List<double> m_topLevels = new List<double>();
+
+        /// <summary>
+        /// 顶部标高(夹层可能涉及多个顶)
+        /// </summary>
+        public string TopLevels
+        {
+            get { return string.Join(";", m_topLevels); }
+        }
+
+        #endregion
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                var document = m_Doc;
+                if (!SetFloorBaseTopRange()) return;
+                var elements = document.GetAllElements();
+                foreach (var element in elements)
+                {
+                    var result = GetCheckResult(element);
+                    if (result != null)
+                        Content.Add(result);
+                }
+
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+            
+        }
+
+        /// <summary>
+        /// 设置当前楼层底部和顶部范围
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="result"></param>
+        private bool SetFloorBaseTopRange()
+        {
+            bool rt = true;
+            var document = m_Doc;
+            try
+            {
+                var sagaPlans = document.GetElements<ViewPlan>()
+                    .Where(t => t.ViewType == ViewType.FloorPlan && t.Name.Contains(RegexConstPattern.SagaSign)).ToList();
+                var curFloor = sagaPlans.FirstOrDefault();
+                if (sagaPlans.Count != 1 || curFloor == null)
+                {
+                    Result = ResultState.Failure;
+                    ResultMsg = "Saga标记不合法,请修正后再进行检查";
+
+                    return false;
+                }
+
+                //设置楼层底部高度
+                m_baseLevel = curFloor.GenLevel.Elevation.FromApi().Round(2);
+
+                //设置楼层顶部高度
+                var levels = m_Doc.GetLevels();
+                var mbiLevels = levels.Where(t => Regex.IsMatch(t.Name, $"{RegexConstPattern.IsMBILevel}") && t.Elevation.IsThan(m_baseLevel)).ToList();
+                foreach (Level level in mbiLevels)
+                {
+                    m_topLevels.Add(level.Elevation.FromApi().Round(2));
+                    if (!Regex.IsMatch(level.Name, $"{RegexConstPattern.IsSandwich}"))
+                    {
+                        break;
+                    }
+                }
+                //当前层为屋顶或屋顶夹层时,顶部限制设置为正无穷
+                if (Regex.IsMatch(curFloor.GenLevel.Name, $"{RegexConstPattern.IsRF}|{RegexConstPattern.IsRFM}"))
+                {
+                    m_topLevels.Add(double.MaxValue);
+                }
+
+
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine(e);
+                rt = false;
+            }
+            return rt;
+        }
+
+        /// <summary>
+        /// 获取检测结果
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        private ElementRangeCheckResult GetCheckResult(Element element)
+        {
+            var result = new ElementRangeCheckResult();
+            result.Id = element.Id.ToString();
+            result.FamilyName = element.GetFamilyName();
+            try
+            {
+                double zb = 0, zt = 0;
+                bool rb = false, rt = false;
+                //需要识别判定的构件
+                DCElementType type = DCElementType.None;
+                bool isBoxInst = false;
+                if (element is Wall wall)
+                {
+                    isBoxInst = true;
+                    zb = wall.GetBaseStaticHeight();
+                    zt = wall.GetTopStaticHeight();
+                    type = DCElementType.Wall;
+                }
+                else if (element.IsSpace())
+                {
+                    var space = element as Space;
+                    isBoxInst = true;
+                    zb = space.GetBaseStaticHeight();
+                    zt = space.GetTopStaticHeight();
+                    type = DCElementType.Space;
+                }
+                else if (element is FamilyInstance)
+                {
+                    if (element.IsAllColumn())
+                    {
+                        var fi = element as FamilyInstance;
+                        isBoxInst = true;
+                        zb = fi.GetBaseStaticHeight();
+                        zt = fi.GetTopStaticHeight();
+                        type = DCElementType.Column;
+                    }
+                    else if (element.IsEquipment() || element.IsEquipmentPart() || element.IsBeacon())
+                    {
+                        zb = element.GetLocationPointMBIXYZ().Z;
+                        type = GetRType(element);
+                    }
+                }
+
+                if (type==DCElementType.None) return null;
+                
+                //冗余,使用时,统一使用单位mm
+                double w = Redundant;
+                zb = zb.FromApi().Round(2);
+                zt = zt.FromApi().Round(2);
+                //构件类型
+                result.Type = type.GetDescription();
+                if (isBoxInst)
+                {
+                    rb = zb.IsBetween(m_baseLevel - w, m_baseLevel);
+                    rt = m_topLevels.Any(t => zt.IsBetween(t - w, t));
+                    string ttip = rb ? "" : "底部";
+                    string ttop = rt ? "" : rb ? "和顶部" : "顶部";
+                    result.HeightRange = $"{zb},{zt}";
+                    result.Result = (rb && rt)?ResultState.Success:ResultState.Failure;
+                    result.ResultMsg = rb && rt ? "" : $"构件范围不满足要求;请检查构件{ttip}{ttop}";
+                }
+                else
+                {
+                    rb = m_topLevels.Any(t => zb.IsBetween(m_baseLevel, t));
+                    result.HeightRange = $"{zb}";
+                    result.Result = (rb) ? ResultState.Success : ResultState.Failure;
+                    result.ResultMsg = rb? "" : $"构件范围不满足要求;请检查构件位置";
+                }
+            }
+            catch (Exception e)
+            {
+                result.Result = ResultState.Failure;
+                result.ResultMsg = "构件范围检查异常";
+            }
+
+
+            return result;
+        }
+
+        /// <summary>
+        /// 获取构件类型
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        private DCElementType GetRType(Element fi)
+        {
+            DCElementType name = DCElementType.None;
+            if (fi.IsEquipment())
+            {
+                name = DCElementType.Equipment;
+            }
+            else if (fi.IsEquipmentPart())
+            {
+                name = DCElementType.EuipmentPart;
+            }
+            else if (fi.IsBeacon())
+            {
+                name = DCElementType.Beacon;
+            }
+            return name;
+        }
+        /// <summary>
+        /// DCElementType
+        /// </summary>
+        public enum DCElementType
+        {
+            [Description("未知")]
+            None,
+            [Description("墙")]
+            Wall,
+            [Description("柱")]
+            Column,
+            [Description("空间")]
+            Space,
+            [Description("设备")]
+            Equipment,
+            [Description("部件")]
+            EuipmentPart,
+            [Description("信标")]
+            Beacon
+        }
+    }
+}

+ 36 - 0
Executer/DataCheck/DataCheck.Mode/ElementRangeCheckResult.cs

@@ -0,0 +1,36 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using Newtonsoft.Json;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class ElementRangeCheckResult : ResultBase
+    {
+        /// <summary>
+        /// id
+        /// </summary>
+        public string Id { get; set; }
+        /// <summary>
+        /// 族名称
+        /// </summary>
+        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+        public string FamilyName { get; set; }
+
+        /// <summary>
+        /// 构件类型
+        /// </summary>
+        public string Type { get; set; }
+        /// <summary>
+        /// 高度范围(单位英寸)
+        /// </summary>
+        public string HeightRange { get; set; }
+    }
+}

+ 74 - 0
Executer/DataCheck/DataCheck.Mode/EquipInSpaceCheck.cs

@@ -0,0 +1,74 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class EquipInSpaceCheck : CheckBase
+    {
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                var document = m_Doc;
+                var elements = document.GetEqEcElements();
+                var rspaces = document.GetSpaces().Where(t => t.IsValidObject).ToList();
+                foreach (Element fi in elements)
+                {
+                    var result = GetCheckResult(fi, rspaces);
+                    Content.Add(result);
+                }
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+        }
+
+        /// <summary>
+        /// 获取检测结果
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        private EquipInSpaceCheckResult GetCheckResult(Element fi, List<Space> spaces)
+        {
+            var result = new EquipInSpaceCheckResult();
+            result.FamilyName = fi.GetFamilyName();
+            result.Id = fi.Id.ToString();
+            var space = fi.GetReferenceSpace(spaces);
+            if (space != null)
+            {
+                result.SpaceId = space.Id.ToString();
+                result.Result = ResultState.Success;
+            }
+            else
+            {
+                result.Result = ResultState.Failure;
+                result.ResultMsg = "请检查设备是否在空间中";
+            }
+
+            return result;
+        }
+    }
+}

+ 32 - 0
Executer/DataCheck/DataCheck.Mode/EquipInSpaceCheckResult.cs

@@ -0,0 +1,32 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using Newtonsoft.Json;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class EquipInSpaceCheckResult : ResultBase
+    {
+        /// <summary>
+        /// id
+        /// </summary>
+        public string Id { get; set; }
+        /// <summary>
+        /// 族名称
+        /// </summary>
+        public string FamilyName { get; set; }
+        /// <summary>
+        /// 所在空间id
+        /// </summary>
+        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+        public string SpaceId { get; set; }
+
+    }
+}

+ 61 - 0
Executer/DataCheck/DataCheck.Mode/EquipPartLocationCheck.cs

@@ -0,0 +1,61 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Linq;
+using Autodesk.Revit.DB;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class EquipPartLocationCheck : CheckBase
+    {
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                var document = m_Doc;
+                var elements = document.GetEqEcElements();
+                var parts = elements.Where(t => t.IsEquipmentPart());
+                foreach (Element fi in parts)
+                {
+                    var result = new EquipPartLocationCheckResult();
+                    result.PartFamilyName = fi.GetFamilyName();
+                    result.PartId = fi.Id.ToString();
+                    var partParent = fi.GetPartParent();
+                    if (partParent == null)
+                    {
+                        result.Result = ResultState.Failure;
+                        result.ResultMsg = "未与设备相交,请检查";
+                    }
+                    else
+                    {
+                        result.Result = ResultState.Success;
+                        result.ResultMsg = $"关联设备的id为{partParent.Id}";
+                    }
+                    Content.Add(result);
+                }
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+           
+
+        }
+    }
+}

+ 25 - 0
Executer/DataCheck/DataCheck.Mode/EquipPartLocationCheckResult.cs

@@ -0,0 +1,25 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class EquipPartLocationCheckResult : ResultBase
+    {
+        /// <summary>
+        /// 部件id
+        /// </summary>
+        public string PartId { get; set; }
+        /// <summary>
+        /// 部件族名称
+        /// </summary>
+        public string PartFamilyName { get; set; }
+    }
+}

+ 84 - 0
Executer/DataCheck/DataCheck.Mode/FamilyNameCheck.cs

@@ -0,0 +1,84 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Linq;
+using Autodesk.Revit.DB;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+using ServiceRevitLib.Utils;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class FamilyNameCheck : CheckBase
+    {
+        public FamilyNameCheck()
+        {
+            ReferenceSheet = "参考-revit分类";
+        }
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                var ccategories = DataCheckRule.GetCodeCheckCategories();
+                var categories = m_Doc.Settings.Categories;
+                foreach (DCR_CodeCheckCategory ccategory in ccategories)
+                {
+                    try
+                    {
+                        var category = categories.get_Item(ccategory.Name);
+                        if (category == null) continue;
+                        BuiltInCategory builtInCategory = (BuiltInCategory)category.Id.IntegerValue;
+                        var elements = m_Doc.GetElements<FamilyInstance>(builtInCategory);
+                        var groupByFamily = elements.GroupBy(t => t.GetFamilyName());
+                        foreach (IGrouping<string, FamilyInstance> grouping in groupByFamily)
+                        {
+                            var subElements = grouping.ToList();
+                            var subElement = subElements.FirstOrDefault();
+                            if (subElement is FamilyInstance fi)
+                            {
+                                var result = new FamilyNameCheckResult();
+                                result.FamilyName = grouping.Key;
+                                if (fi.IsEquipment() || fi.IsEquipmentPart() || fi.IsBeacon())
+                                {
+                                    result.Result = ResultState.Success;
+                                }
+                                else
+                                {
+                                    result.Result = ResultState.Failure;
+                                    result.ResultMsg = "请检查族名称编码是否符合要求";
+                                }
+                                Content.Add(result);
+                            }
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        Console.WriteLine(e);
+                    }
+                }
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+         
+
+        }
+        
+    }
+}

+ 21 - 0
Executer/DataCheck/DataCheck.Mode/FamilyNameCheckResult.cs

@@ -0,0 +1,21 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class FamilyNameCheckResult : ResultBase
+    {
+        /// <summary>
+        /// 族名称
+        /// </summary>
+        public string FamilyName { get; set; }
+    }
+}

+ 86 - 0
Executer/DataCheck/DataCheck.Mode/ParameterIntegrityCheck.cs

@@ -0,0 +1,86 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Autodesk.Revit.DB;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Common;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class ParameterIntegrityCheck : CheckBase
+    {
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                var doc = m_Doc;
+                var instances = doc.GetEqEcElements();
+                var familyGroups = instances.GroupBy(t => t.GetFamilyName());
+                foreach (IGrouping<string, Element> familyGroup in familyGroups)
+                {
+                    Element fi = familyGroup.FirstOrDefault();
+                    if (fi == null) continue;
+                    var result = GetCheckResult(fi);
+                    if (result == null) continue;
+                    result.FamilyName = familyGroup.Key;
+                    Content.Add(result);
+                }
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+           
+
+        }
+
+
+        /// <summary>
+        /// 获取检测结果
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        private ParameterIntegrityCheckResult GetCheckResult(Element fi)
+        {
+            //检查项
+            var checkParamNames = new List<string>() { MBIConst.EquipLocalName, MBIConst.EquipLocalID };
+
+            var result = new ParameterIntegrityCheckResult();
+            List<string> list = new List<string>();
+            foreach (var paramName in checkParamNames)
+            {
+                var parameter = fi.GetParameter(paramName);
+                if (parameter == null)
+                    list.Add(paramName);
+            }
+            if (list.Any())
+            {
+                result.Result = ResultState.Failure;
+                result.ResultMsg = $"缺失的参数为:{string.Join("、", list)}";
+            }
+            else
+            {
+                result.Result = ResultState.Success;
+            }
+            return result;
+        }
+    }
+}

+ 22 - 0
Executer/DataCheck/DataCheck.Mode/ParameterIntegrityCheckResult.cs

@@ -0,0 +1,22 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class ParameterIntegrityCheckResult : ResultBase
+    {
+        /// <summary>
+        /// 族名称
+        /// </summary>
+        public string FamilyName { get; set; }
+        
+    }
+}

+ 150 - 0
Executer/DataCheck/DataCheck.Mode/PipeCheck.cs

@@ -0,0 +1,150 @@
+/* ==============================================================================
+ * 功能描述:管网检查
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using Autodesk.Revit.DB;
+using SAGA.DotNetUtils.Extend;
+using SAGA.RevitUtils.Extends;
+using SAGA.RevitUtils.MEP;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class PipeCheck : CheckBase
+    {
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                var document = m_Doc;
+
+                var elements = document.FilterElements<MEPCurve>().ToList();
+                foreach (var element in elements)
+                {
+                    if (element.IsStart())
+                    {
+                        //标记立管,所有连接点都未记录则删除                 
+                        //if (!connectors.Any(c => c.IsConnected))
+                        //{
+                        //    item.ErrorCode = "001";
+                        //    reportItem.ResultItems.Add(item);                      
+                        //}
+                        continue;
+                    }
+                    var item = new PipeCheckResult();
+                    // 如果为软管,则不导出。软管的系统名称为空
+                    var tempSystem = element.GetSystemTypeName();
+                    if (tempSystem.IsNullOrEmpty()) continue;
+                    item.SystemName = tempSystem;
+                    item.Id = element.Id.ToString();
+                    var code = GetErrorCode(element, item.SystemName);
+                    if (IsNeedExport(code))
+                    {
+                        item.Result = ResultState.Failure;
+                        item.ResultMsg = GetErrorDescription(code);
+                        Content.Add(item);
+                    }
+                }
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+           
+
+        }
+        /// <summary>
+        /// 获取错误码
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="systemName"></param>
+        /// <returns></returns>
+        private PipeCheckErrorCode GetErrorCode(Element element,string systemName)
+        {
+            PipeCheckErrorCode errorCode = PipeCheckErrorCode.Code_000;
+            Domain[] domains = new Domain[] { Domain.DomainPiping, Domain.DomainHvac };
+            do
+            {
+                foreach (Domain domain in domains)
+                {
+                    var connectors = element.GetConnectors(domain);
+                    if (connectors.Any(c => !c.IsConnected))
+                    {
+                        errorCode = PipeCheckErrorCode.Code_001;
+                    }
+                }
+                if (errorCode == PipeCheckErrorCode.Code_001 && element.GetLocationCurve() is Line line)
+                {
+                    //一端不连接的立管不导出
+                    if (line.Direction.IsParallel(XYZ.BasisZ))
+                    {
+                        errorCode = PipeCheckErrorCode.Code_003;
+                    }
+                }
+                var endElements = element.GetFirstElements(null, e => e is MEPCurve || e.IsEquipment());
+                List<MEPCurve> curves = endElements.OfType<MEPCurve>().ToList();
+                foreach (var mepCurve in curves)
+                {
+                    var tempSystem = mepCurve.GetSystemTypeName();
+                    if (tempSystem.IsNullOrEmpty()) continue;
+                    if (systemName != tempSystem)
+                    {
+                        errorCode = PipeCheckErrorCode.Code_002;
+                        break;
+                    }
+                }
+
+            } while (false);
+
+            return errorCode;
+        }
+        /// <summary>
+        /// 获取错误描述
+        /// </summary>
+        /// <param name="errorCode"></param>
+        /// <returns></returns>
+        private string GetErrorDescription(PipeCheckErrorCode errorCode)
+        {
+            string description = errorCode.GetDescription()+",请检查";
+            return description;
+        }
+        /// <summary>
+        /// 是否需要导出
+        /// </summary>
+        /// <param name="errorCode"></param>
+        /// <returns></returns>
+        private bool IsNeedExport(PipeCheckErrorCode errorCode)
+        {
+            return errorCode == PipeCheckErrorCode.Code_001 || errorCode == PipeCheckErrorCode.Code_002;
+        }
+
+        enum PipeCheckErrorCode
+        {
+            [Description("管段连接正确")]
+            Code_000,
+            [Description("末端未连接任何设备")]
+            Code_001,
+            [Description("管道两端连接了不同类型的管道")]
+            Code_002,
+            Code_003,
+            [Description("误报")]
+            Code_004
+        }
+    }
+}

+ 26 - 0
Executer/DataCheck/DataCheck.Mode/PipeCheckResult.cs

@@ -0,0 +1,26 @@
+/* ==============================================================================
+ * 功能描述:管网检查结果
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class PipeCheckResult : ResultBase
+    {
+        /// <summary>
+        /// id
+        /// </summary>
+        public string Id { get; set; }
+        /// <summary>
+        /// 系统名称
+        /// </summary>
+        public string SystemName { get; set; }
+        
+    }
+}

+ 35 - 0
Executer/DataCheck/DataCheck.Mode/ResultBase.cs

@@ -0,0 +1,35 @@
+/* ==============================================================================
+ * 功能描述:
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:24:04
+ * ==============================================================================*/
+
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace ServiceRevitLib.Mode
+{
+    /// <summary>
+    /// CheckResultBase
+    /// </summary>
+    public class ResultBase
+    {
+        public ResultBase()
+        {
+            Result = ResultState.Success;
+        }
+        /// <summary>
+        /// 成功或失败结果描述
+        /// </summary>
+        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+        public string ResultMsg { get; set; }
+
+        /// <summary>
+        /// 结果
+        /// </summary>
+        [JsonConverter(typeof(StringEnumConverter))]
+        public ResultState Result { get; set; }
+
+
+    }
+}

+ 17 - 0
Executer/DataCheck/DataCheck.Mode/ResultState.cs

@@ -0,0 +1,17 @@
+/* ==============================================================================
+ * 功能描述:结果的状态
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:29:04
+ * ==============================================================================*/
+
+namespace ServiceRevitLib.Mode
+{
+    /// <summary>
+    /// ResultState
+    /// </summary>
+    public enum ResultState
+    {
+        Failure=0,
+        Success,
+    }
+}

+ 100 - 0
Executer/DataCheck/DataCheck.Mode/SagaCheck.cs

@@ -0,0 +1,100 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Autodesk.Revit.DB;
+using SAGA.DotNetUtils.Extend;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Common;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class SagaCheck : CheckBase
+    {
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                string resultMsg = null;
+                ResultState resultState = 0;
+                string planName = "";
+
+                //判断是否存在Saga标记
+                var document = m_Doc;
+                var sagaPlans = document.GetElements<ViewPlan>()
+                    .Where(t => t.ViewType == ViewType.FloorPlan && t.Name.Contains(RegexConstPattern.SagaSign)).ToList();
+                if (sagaPlans.Count == 0)
+                {
+                    resultState = ResultState.Failure;
+                    resultMsg = "缺少saga标记";
+                }
+                else if (sagaPlans.Count() >= 2)
+                {
+                    resultState = ResultState.Failure;
+                    resultMsg = "有多个saga标记";
+                }
+                else
+                {
+                    //只有一个saga标记
+                    var sagaPlan = sagaPlans.FirstOrDefault();
+                    if (sagaPlan != null)
+                    {
+                        planName = sagaPlan.Name;
+                        //打标记的楼层名称必需为指定格式;B1,B1M,F1,F1M,RFM,RF
+                        if (Regex.IsMatch(planName, $"{RegexConstPattern.IsMBIView}"))
+                        {
+                            var rfLevel = document.GetLevels().FirstOrDefault(t =>
+                                System.Text.RegularExpressions.Regex.IsMatch(t.Name, $"{RegexConstPattern.IsRF}"));
+                            if (rfLevel == null)
+                            {
+                                resultState = ResultState.Failure;
+                                resultMsg = $"缺少RF标高";
+                            }
+                            else
+                            {
+                                if (rfLevel.Elevation.IsThanEq(sagaPlan.GenLevel.Elevation))
+                                {
+                                    resultState = ResultState.Success;
+                                }
+                                else
+                                {
+                                    resultState = ResultState.Failure;
+                                    resultMsg = $"RF标高的位置不正确,请检查";
+                                }
+                            }
+                        }
+                        else
+                        {
+                            resultState = ResultState.Failure;
+                            resultMsg = $"楼层 {planName} 不符合楼层命名规范";
+                        }
+                    }
+                }
+
+                Content.Add(new SagaCheckResult() { PlanName = planName, Result = resultState, ResultMsg = resultMsg });
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+           
+
+        }
+    }
+}

+ 21 - 0
Executer/DataCheck/DataCheck.Mode/SagaCheckResult.cs

@@ -0,0 +1,21 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class SagaCheckResult: ResultBase
+    {
+        /// <summary>
+        /// Saga视图的名称
+        /// </summary>
+        public string PlanName { get; set; }
+    }
+}

+ 97 - 0
Executer/DataCheck/DataCheck.Mode/SystemNameCheck.cs

@@ -0,0 +1,97 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using SAGA.RevitUtils.MEP;
+using ServiceRevitLib.Mode;
+using ServiceRevitLib.Utils;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class SystemNameCheck : CheckBase
+    {
+        public SystemNameCheck()
+        {
+            ReferenceSheet = "参考-可识别的系统名称";
+        }
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                m_MEPSystems = DataCheckRule.GetMepSystems();
+
+                var mepsystemTypes = new List<MEPSystemType>();
+                mepsystemTypes.AddRange(m_Doc.GetMechanicalSystemTypes());
+                mepsystemTypes.AddRange(m_Doc.GetPipingSystemTypes());
+                foreach (var t in mepsystemTypes)
+                {
+                    var result = GetCheckResult(t);
+                    Content.Add(result);
+                }
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+           
+
+        }
+        private List<DCR_MEPSystem> m_MEPSystems;
+
+        /// <summary>
+        /// 获取检测结果
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        private SystemNameCheckResult GetCheckResult(MEPSystemType system)
+        {
+            var result = new SystemNameCheckResult();
+            string systemName = system.Name;
+            result.SystemName = systemName;
+            result.SystemType = system is MechanicalSystemType ? "风管系统" : "管道系统";
+            
+            var item = m_MEPSystems.Where(t => SystemNameIsEqual(systemName, t.Name));
+            if (item.Any())
+            {
+                result.Result = ResultState.Success;
+            }
+            else
+            {
+                result.Result = ResultState.Failure;
+                result.ResultMsg = $"未知的系统名称,请按照系统类型命名规范修改";
+            }
+            
+            return result;
+        }
+        /// <summary>
+        /// 系统名称相等,模型中的系统名称包含就定义名称即可
+        /// </summary>
+        /// <param name="originName"></param>
+        /// <param name="targetName"></param>
+        /// <returns></returns>
+        private bool SystemNameIsEqual(string originName, string targetName)
+        {
+            bool result = false;
+            string n1 = originName.ToLower();
+            string n2 = targetName.ToLower();
+            return n1.Equals(n2);
+        }
+    }
+}

+ 26 - 0
Executer/DataCheck/DataCheck.Mode/SystemNameCheckResult.cs

@@ -0,0 +1,26 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class SystemNameCheckResult : ResultBase
+    {
+        /// <summary>
+        /// 系统名称
+        /// </summary>
+        public string SystemName { get; set; }
+        /// <summary>
+        /// 系统类型
+        /// </summary>
+        public string SystemType { get; set; }
+        
+    }
+}

+ 131 - 0
Executer/DataCheck/DataCheck.Mode/SystemReferEquipCheck.cs

@@ -0,0 +1,131 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Autodesk.Revit.DB;
+using SAGA.DotNetUtils.Logger;
+using SAGA.RevitUtils.MEP;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+using ServiceRevitLib.Utils;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class SystemReferEquipCheck : CheckBase
+    {
+        public SystemReferEquipCheck()
+        {
+            ReferenceSheet = "参考-管网及相关设备";
+        }
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                m_EquipReferSystems = DataCheckRule.GetEquipReferSystems();
+
+                var elements = m_Doc.GetEqEcElements();
+                foreach (Element element in elements)
+                {
+                    var result = GetCheckResult(element);
+                    if (result == null) continue;
+                    Content.Add(result);
+                }
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+          
+
+        }
+
+        private List<DCR_EquipReferSystem> m_EquipReferSystems;
+     
+
+        /// <summary>
+        /// 获取检测结果
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        private SystemReferEquipCheckResult GetCheckResult(Element element)
+        {
+            var result = new SystemReferEquipCheckResult();
+            var code = element.GetFamilyCode();
+            // 可以与设备连接的系统
+            var referSystems = m_EquipReferSystems.FirstOrDefault(t => t.EquipName == code)?.Systems ?? new List<string>();
+            if (referSystems.Count == 0) return null;
+
+            result.FamilyName = element.GetFamilyName();
+            result.Id = element.Id.ToString();
+
+            var tuple = CheckConType(element, referSystems);
+            if (tuple.Item2.Any())
+            {
+                result.ResultMsg = $"连接件所连接的管道系统与规范不一致,请检查";
+                result.UnPassSystems += string.Join("、", tuple.Item2.ToArray());
+                result.Result = ResultState.Failure;
+            }
+            else
+            {
+                result.Result = ResultState.Success;
+            }
+            result.PassSystems += string.Join("、", tuple.Item1.ToArray());
+
+            return result;
+        }
+
+        /// <summary>
+        /// 检查连接件连接的管道系统是否符合规范
+        /// </summary>
+        /// <param name="result">符合要求的系统名称</param>
+        /// <param name="domain">不符合要求的系统名称</param>
+        private Tuple<List<string>, List<string>> CheckConType(Element element, List<string> referSystems)
+        {
+            List<string> passList = new List<string>();
+            List<string> unpassList = new List<string>();
+
+            var connectors = element.GetAllConnectors();
+            foreach (Connector connector in connectors)
+            {
+                try
+                {
+                    var mepSystem = connector.MEPSystem;
+                    if (mepSystem == null) continue;
+                    var elementId = mepSystem.GetTypeId();
+                    var type = element.Document.GetElement(elementId);
+                    if (!referSystems.Contains(type.Name))
+                    {
+                        unpassList.Add(type.Name);
+                    }
+                    else
+                    {
+                        passList.Add(type.Name);
+                    }
+                }
+                catch (Exception e)
+                {
+                    Log4Net.Info($"读取连接件系统错误。Id:{element.Id},Path:{element.Document.PathName}");
+                }
+            }
+
+            return new Tuple<List<string>, List<string>>(passList, unpassList);
+        }
+
+
+    }
+}

+ 38 - 0
Executer/DataCheck/DataCheck.Mode/SystemReferEquipCheckResult.cs

@@ -0,0 +1,38 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using Newtonsoft.Json;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class SystemReferEquipCheckResult : ResultBase
+    {
+        /// <summary>
+        /// id
+        /// </summary>
+        public string Id { get; set; }
+        /// <summary>
+        /// 族名称
+        /// </summary>
+        public string FamilyName { get; set; }
+
+        /// <summary>
+        /// 合法的系统名称集合
+        /// </summary>
+        public string PassSystems { get; set; }
+        /// <summary>
+        /// 不合法的系统名称集合
+        /// </summary>
+        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+        public string UnPassSystems { get; set; }
+
+
+    }
+}

+ 55 - 0
Executer/DataCheck/DataCheck.Mode/UnitCheck.cs

@@ -0,0 +1,55 @@
+/* ==============================================================================
+ * 功能描述:SagaCheck  
+ * 创 建 者:Garrett
+ * 创建日期:2019/6/11 16:09:09
+ * ==============================================================================*/
+
+using System;
+using Autodesk.Revit.DB;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheck
+    /// </summary>
+    class UnitCheck : CheckBase
+    {
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                string resultMsg = null;
+                ResultState resultState = ResultState.Failure;
+                string unit = "";
+
+                var formatOptions = m_Doc.GetUnits().GetFormatOptions(UnitType.UT_Length);
+                var ismmUnit = formatOptions.DisplayUnits == DisplayUnitType.DUT_MILLIMETERS;
+                unit = formatOptions.DisplayUnits.ToString();
+                if (!ismmUnit)
+                {
+                    resultMsg = "单位异常,请修改长度单位为毫米(mm)";
+                    resultState = ResultState.Failure;
+                }
+                else
+                {
+                    resultState = ResultState.Success;
+                }
+
+                Content.Add(new UnitCheckResult() { Unit = unit, Result = resultState, ResultMsg = resultMsg });
+
+                #endregion
+            }
+            catch (Exception e)
+            {
+                Result = ResultState.Failure;
+                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+            }
+           
+        }
+    }
+}

+ 21 - 0
Executer/DataCheck/DataCheck.Mode/UnitCheckResult.cs

@@ -0,0 +1,21 @@
+/* ==============================================================================
+ * 功能描述:SagaCheckResult  
+ * 创 建 者:Garrett
+ * 创建日期:2019/5/31 16:20:46
+ * ==============================================================================*/
+
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// SagaCheckResult
+    /// </summary>
+    class UnitCheckResult : ResultBase
+    {
+        /// <summary>
+        /// 项目单位
+        /// </summary>
+        public string Unit { get; set; }
+    }
+}

+ 77 - 0
Executer/DataCheck/DataCheck.Mode/XYZOverlapCheck.cs

@@ -0,0 +1,77 @@
+/* ==============================================================================
+ * 功能描述:xyz坐标重叠检查
+ * 创 建 者:Garrett
+ * 创建日期:2018/10/23 15:08:55
+ * ==============================================================================*/
+
+using System;
+using System.Linq;
+using Autodesk.Revit.DB;
+using SAGA.RevitUtils;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Extend;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib.DataCheck.Mode
+{
+    /// <summary>
+    /// 
+    /// </summary>
+    class XYZOverlapCheck : CheckBase
+    {
+        public override void Check()
+        {
+            try
+            {
+                base.Check();
+
+                #region
+
+                var doc = m_Doc;
+                var instances = doc.GetFamilyInstances().Where(t=>t.GetLocationPoint()!=null);
+                var groups = instances.GroupBy(t => t.GetLocationPoint(), new XyzEqualComparer(0.01d));
+                foreach (var group in groups)
+                {
+                    var key = group.Key;
+                    if (key == null) continue;
+                    var list = group.ToList();
+                    if (list.Count == 1) continue;
+                    var fi = list.FirstOrDefault();
+                    var result = GetCheckResult(fi);
+                    list.Remove(fi);
+                    if (result == null) continue;
+
+                    result.ResultMsg = $"与{string.Join(",", list.Select(t => t.Id.ToString()))}的坐标发生重叠,请检查";
+                    Content.Add(result);
+                }
+                #endregion
+            }
+            catch (Exception e)
+            {
+                //Result = ResultState.Failure;
+                //ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
+                Result = ResultState.Success;
+                ResultMsg = $"";
+            }
+        }
+        /// <summary>
+        /// 获取检测结果
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        private XYZOverlapCheckResult GetCheckResult(Element fi)
+        {
+            var result = new XYZOverlapCheckResult(){ Result = ResultState.Failure};
+            result.Id = fi.Id.ToString();
+            result.FamilyName = fi.GetFamilyName();
+            return result;
+        }
+    }
+
+    class XYZOverlapCheckResult : ResultBase
+    {
+        public string FamilyName { get; set; }
+
+        public string Id { get; set; }
+    }
+}

BIN
Executer/DataCheck/DataCheckResource/模型检查结果输出格式-模版.xlsx


+ 38 - 0
Executer/DataCheck/Extend/DocExtend.cs

@@ -0,0 +1,38 @@
+/* ==============================================================================
+ * 功能描述:DocExtend  
+ * 创 建 者:Garrett
+ * 创建日期:2018/6/11 16:00:53
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Autodesk.Revit.DB;
+using SAGA.DotNetUtils;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Common;
+
+namespace ServiceRevitLib.Extend
+{
+    /// <summary>
+    /// DocExtend
+    /// </summary>
+    public static class DocExtend
+    {
+        /// <summary>
+        /// 获取所有的Docment中,设备或者部件
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="bic"></param>
+        /// <returns></returns>
+        public static List<Element> GetEqEcElements(this Document doc)
+        {
+            List<Element> elements = new List<Element>();
+            //elements.AddRange(doc.GetElements(typeof(Wall)));
+            elements.AddRange(doc.GetElements(typeof(FamilyInstance)));
+            return elements.Where(t=>t.IsMbiEquipment()).ToList();
+        }
+    }
+}

+ 244 - 0
Executer/DataCheck/Extend/ElementExtend.cs

@@ -0,0 +1,244 @@
+/* ==============================================================================
+ * 功能描述:ElementExtend  
+ * 创 建 者:Garrett
+ * 创建日期:2018/5/28 16:41:22
+ * ==============================================================================*/
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using SAGA.DotNetUtils;
+using SAGA.DotNetUtils.Extend;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Common;
+
+namespace ServiceRevitLib.Extend
+{
+    /// <summary>
+    /// ElementExtend
+    /// </summary>
+    public static class ElementExtend
+    {
+        /// <summary>
+        /// 判断元素是否是开始元素
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static bool IsStart(this Element element)
+        {
+            return (element.GetParameterString(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS) ?? string.Empty).StartsWith(MBIConst.StartFlag);
+        }
+        /// <summary>
+        /// 判断是否为设备 设备族为4位
+        /// ATVR - 多联机 - 室内机 - 双向气流 - 天花板嵌入式
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        public static bool IsEquipment(this Element element)
+        {
+            bool result = false;
+            //if (element is Wall wall)
+            //{//添加幕墙识别
+            //    result = wall.WallType.Kind == WallKind.Curtain;
+
+            //}
+            //else
+            if (element is FamilyInstance fi)
+            {
+                var family = fi.GetFamilyName();
+                result = Regex.IsMatch(family, $"{RegexConstPattern.IsEquip}");
+            }
+
+            return result;
+        }
+        /// <summary>
+        /// 判断是否为设备部件 设备族为6位
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        public static bool IsEquipmentPart(this Element element)
+        {
+            bool result = false;
+            if (element is FamilyInstance fi)
+            {
+                var family = fi.GetFamilyName();
+                result = Regex.IsMatch(family, $"{RegexConstPattern.IsEquipPart}");
+            }
+
+            return result;
+        }
+        /// <summary>
+        /// 广义mbi设备包含设备和部件
+        /// </summary>
+        /// <param name="family"></param>
+        /// <returns></returns>
+        public static bool IsMbiEquipment(this Element element)
+        {
+            return element.IsEquipment()||element.IsEquipmentPart();
+        }
+        /// <summary>
+        /// 判断是否为信标
+        /// </summary>
+        /// <param name="elem"></param>
+        /// <returns></returns>
+        public static bool IsBeacon(this Element elem)
+        {
+            var family = elem.GetFamilyName();
+            return family != null && (Regex.IsMatch(family, RegexConstPattern.IsBeacon));
+        }
+
+        /// <summary>
+        /// 判断是否为空间,判断周长是否为零
+        /// 如果周长为零,是删除的空间
+        /// </summary>
+        /// <param name="elem"></param>
+        /// <param name="ischeckzero">是否检查周长为零</param>
+        /// <returns></returns>
+        public static bool IsSpace(this Element elem, bool ischeckzero = true)
+        {
+            var isspace = false;
+            if (elem is Space space)
+            {
+                //空间比较特殊,周长为零就相当于删除
+                isspace = !ischeckzero || !(space.IsDeleteSpace());
+                //限制所用空间的阶段
+                //isspace = isspace && space.IsPhase1Space();
+            }
+
+            return isspace;
+        }
+        /// <summary>
+        /// 获取MBI的定位点
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static XYZ GetLocationPointMBIXYZ(this Element element)
+        {
+            ////定位点不可靠,未来可能会更改为Box的中心点
+            //XYZ bimXyz = element.GetLocationPoint();
+            //if (element is FamilyInstance fi)
+            //{
+            //    var family = fi.GetFamily();
+            //    if (family.IsInPlace)
+            //    {
+            //        bimXyz = fi.GetBoxCenter();
+            //    }
+            //}
+            //定位点改为Box中心点 
+            XYZ bimXyz = element.GetBoxCenter();
+
+            return bimXyz;
+        }
+        /// <summary>
+        /// 获取MBI存储的位置信息
+        /// </summary>
+        /// <returns></returns>
+        public static string GetLocationPointMBI(this Element element)
+        {
+            string str = ",,";
+            XYZ bimXyz = element.GetLocationPointMBIXYZ();
+            if (bimXyz != null)
+            {
+                str = bimXyz.FromApi().ToString(null);
+            };
+            //JObject jObject = new JObject();
+            //jObject.Add("X", bimXyz.X);
+            //jObject.Add("Y", bimXyz.Y);
+            //jObject.Add("Z", bimXyz.Z);
+            //return (new JArray(jObject)).ToString();
+            return str;
+        }
+        /// <summary>
+        /// 获取MBI存储的位置信息
+        /// </summary>
+        /// <returns></returns>
+        public static XYZ ToXyz(this string xyzstr)
+        {
+            XYZ xyz = null;
+            var strs = xyzstr.Split(',');
+            if (strs.Length == 3)
+            {
+                xyz = new XYZ(strs[0].ToDouble(), strs[1].ToDouble(), strs[2].ToDouble());
+            }
+            //JObject jObject = new JObject();
+            //jObject.Add("X", bimXyz.X);
+            //jObject.Add("Y", bimXyz.Y);
+            //jObject.Add("Z", bimXyz.Z);
+            //return (new JArray(jObject)).ToString();
+            return xyz;
+        }
+
+        /// <summary>
+        /// 获取设备的种族类型编码 ATFC
+        /// 族名称的命名规则:ATFC-风机盘管
+        /// </summary>
+        /// <returns></returns>
+        public static string GetFamilyCode(this Element element)
+        {          
+            string code = "";
+            if (element is FamilyInstance fi)
+            {
+                string familyName = fi.GetFamilyName();
+                if (familyName == null) return code;
+                //族名称的命名规则:ATFC-风机盘管
+                int index = familyName.IndexOf('-');
+                if (index != -1 && index + 1 != familyName.Length)
+                    code = familyName.Substring(0, familyName.IndexOf('-'));
+                //移除前面和后面的空格
+                code = code.Trim();
+            }
+
+            return code;
+        }
+
+        public static string GetFamilyName(this Element element)
+        {
+            return element.GetFamily()?.Name;
+        }
+        /// <summary>
+        /// 获取关联的空间
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        public static Space GetReferenceSpace(this Element element, List<Space> spaces = null)
+        {
+            Space space = null;
+            if (element is FamilyInstance fi)
+            {
+                space = fi.Space;
+                if (space != null) return space;
+                if (spaces == null)
+                    spaces = fi.Document.GetSpaces().Where(t => t.IsValidObject).ToList();
+                var origin1 = fi.GetLocationPointMBIXYZ();
+                foreach (Space tempSpace in spaces)
+                {
+                    //没有Space属性,取定位点,判断定位点所在空间
+                    if (tempSpace.IsPointInSpace(origin1))
+                    {
+                        space = tempSpace;
+                        break;
+                    }
+                }
+            }
+
+            return space;
+        }
+
+        /// <summary>
+        /// 获取部件所关联的设备
+        /// </summary>
+        /// <param name="fi"></param>
+        /// <returns></returns>
+        public static Element GetPartParent(this Element element)
+        {
+            string code = element?.GetFamily().Name.Substring(0, 4); ;
+            if (code.IsNullOrEmpty()) return null;
+            //构件所关联的设备
+            var parentInst = element?.Document.GetElements(new ElementIntersectsElementFilter(element))
+                .FirstOrDefault(t => !t.Id.IsEqual(element.Id) && t.GetFamilyCode() == code);
+            return parentInst;
+        }
+    }
+}

+ 48 - 0
Executer/DataCheck/Extend/MepExtension.cs

@@ -0,0 +1,48 @@
+/* ==============================================================================
+ * 功能描述:MepExtension  
+ * 创 建 者:Garrett
+ * 创建日期:2019/9/20 16:20:45
+ * ==============================================================================*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using Autodesk.Revit.DB.Plumbing;
+using SAGA.RevitUtils.Extends;
+
+namespace ServiceRevitLib.Extend
+{
+    /// <summary>
+    /// MepExtension
+    /// </summary>
+    public static class MepExtension
+    {
+        /// <summary>
+        /// 获取系统名称
+        /// </summary>
+        /// <param name="mepCurve"></param>
+        /// <returns></returns>
+        public static string GetSystemTypeName(this MEPCurve mepCurve)
+        {
+            Parameter parameter = null;
+            do
+            {
+                if (mepCurve is Pipe pipe)
+                {
+                    parameter = pipe.GetParameter(BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM);
+                    break;
+                }
+                if (mepCurve is Duct duct)
+                {
+                    parameter = duct.GetParameter(BuiltInParameter.RBS_DUCT_SYSTEM_TYPE_PARAM);
+                }
+            } while (false);
+
+            return parameter?.AsValueString() ?? string.Empty;
+        }
+        
+    }
+}

+ 37 - 0
Executer/DataCheck/Extend/SpaceExtend.cs

@@ -0,0 +1,37 @@
+/* ==============================================================================
+ * 功能描述:SpaceExtend  
+ * 创 建 者:Garrett
+ * 创建日期:2019/12/6 14:52:05
+ * ==============================================================================*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB.Mechanical;
+using SAGA.DotNetUtils.Extend;
+using ServiceRevitLib.Common;
+
+namespace ServiceRevitLib.Extend
+{
+    /// <summary>
+    /// SpaceExtend
+    /// </summary>
+    public static class SpaceExtend
+    {
+        /// <summary>
+        /// 手动删除的空间,仅在明细表中可见
+        /// </summary>
+        /// <param name="space"></param>
+        /// <returns></returns>
+        public static bool IsDeleteSpace(this Space space)
+        {
+            //周长
+            double perimeter = space.Perimeter;
+            //面积
+            double area = space.Area;
+            //空间比较特殊,周长为零就相当于删除
+            return (perimeter.IsZero(MBIConst.SpacePerimeterTolerance)) || (area.IsZero(MBIConst.SpaceAreaTolerance));
+        }
+    }
+}

+ 36 - 0
Executer/DataCheck/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("ServiceRevitLib")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ServiceRevitLib")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("7b748b09-dc20-4406-85a3-101e7833f8ce")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+// 方法是按如下所示使用“*”: :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 132 - 0
Executer/DataCheck/ServiceDataCheck.csproj

@@ -0,0 +1,132 @@
+<?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>{7B748B09-DC20-4406-85A3-101E7833F8CE}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>ServiceRevitLib</RootNamespace>
+    <AssemblyName>ServiceRevitLib</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\OutputDll\</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>..\..\OutputDll\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Newtonsoft.Json.11.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="NPOI, Version=2.2.1.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\NPOI.2.2.1\lib\net40\NPOI.dll</HintPath>
+    </Reference>
+    <Reference Include="NPOI.OOXML, Version=2.2.1.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\NPOI.2.2.1\lib\net40\NPOI.OOXML.dll</HintPath>
+    </Reference>
+    <Reference Include="NPOI.OpenXml4Net, Version=2.2.1.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\NPOI.2.2.1\lib\net40\NPOI.OpenXml4Net.dll</HintPath>
+    </Reference>
+    <Reference Include="NPOI.OpenXmlFormats, Version=2.2.1.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\NPOI.2.2.1\lib\net40\NPOI.OpenXmlFormats.dll</HintPath>
+    </Reference>
+    <Reference Include="RevitAPI, Version=17.0.0.0, Culture=neutral, processorArchitecture=AMD64">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\RevitDlls\RevitAPI.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="SAGA.DotNetUtils, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\RevitDlls\SAGA.DotNetUtils.dll</HintPath>
+    </Reference>
+    <Reference Include="SAGA.RevitUtils, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\RevitDlls\SAGA.RevitUtils.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <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="CheckFactory.cs" />
+    <Compile Include="Common\MBIConst.cs" />
+    <Compile Include="Common\RegexConstPattern.cs" />
+    <Compile Include="DataCheck.Mode\XYZOverlapCheck.cs" />
+    <Compile Include="DataCheck.Mode\PipeCheck.cs" />
+    <Compile Include="DataCheck.Mode\PipeCheckResult.cs" />
+    <Compile Include="Extend\DocExtend.cs" />
+    <Compile Include="Extend\ElementExtend.cs" />
+    <Compile Include="DataCheck.Mode\CheckBase.cs" />
+    <Compile Include="DataCheck.Mode\EquipInSpaceCheck.cs" />
+    <Compile Include="DataCheck.Mode\SystemReferEquipCheck.cs" />
+    <Compile Include="DataCheck.Mode\ParameterIntegrityCheck.cs" />
+    <Compile Include="DataCheck.Mode\SystemNameCheck.cs" />
+    <Compile Include="DataCheck.Mode\EquipInSpaceCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\SystemReferEquipCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\ParameterIntegrityCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\SystemNameCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\EquipPartLocationCheck.cs" />
+    <Compile Include="DataCheck.Mode\ColumnCheck.cs" />
+    <Compile Include="DataCheck.Mode\ElementRangeCheck.cs" />
+    <Compile Include="DataCheck.Mode\ConnectorCheck.cs" />
+    <Compile Include="DataCheck.Mode\FamilyNameCheck.cs" />
+    <Compile Include="DataCheck.Mode\EquipPartLocationCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\ColumnCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\ElementRangeCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\ConnectorCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\FamilyNameCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\UnitCheck.cs" />
+    <Compile Include="DataCheck.Mode\SagaCheck.cs" />
+    <Compile Include="DataCheck.Mode\UnitCheckResult.cs" />
+    <Compile Include="DataCheck.Mode\SagaCheckResult.cs" />
+    <Compile Include="Extend\MepExtension.cs" />
+    <Compile Include="Extend\SpaceExtend.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TestCommand.cs" />
+    <Compile Include="Utils\DataCheckRule.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="DataCheckResource\模型检查结果输出格式-模版.xlsx">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <None Include="app.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\MBIRevitBase\MBIRevitBase.csproj">
+      <Project>{2bc3da7b-57cb-4d9d-8afa-888ea4d8da87}</Project>
+      <Name>MBIRevitBase</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 64 - 0
Executer/DataCheck/TestCommand.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Autodesk.Revit.Attributes;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using SAGA.DotNetUtils.Data;
+using SAGA.DotNetUtils.Geometry;
+using SAGA.RevitUtils;
+using SAGA.RevitUtils.Extends;
+using ServiceRevitLib.Mode;
+
+namespace ServiceRevitLib
+{
+    #region 测试命令
+
+    public class ServiceDataCheckTest
+    {
+        public static string Check(Document doc)
+        {
+            string result = null;
+            try
+            {
+                var factory = new CheckFactory();
+                
+                factory.SetCheckItems(ConfigurationManager.AppSettings["CheckItems"]);
+                factory.Check(doc);
+                result = Serialze(factory);
+#if DEBUG
+                string fileName = DateTime.Now.ToString("yyyyMMddHHmmss");
+                string path = Path.Combine(@"D:\", $"DataCheck{fileName}.json");
+                File.WriteAllText(path, result);
+#endif
+            }
+            catch (Exception e)
+            {
+                result = Serialze(ResultBase.Exception(e.Message));
+            }
+
+            return result;
+        }
+
+        public static string Serialze(object obj)
+        {
+            JsonSerializerSettings jsetting = CreateDefaultSettings();
+            var result = JsonConvert.SerializeObject(obj, jsetting);
+            return result;
+        }
+        private static JsonSerializerSettings CreateDefaultSettings()
+        {
+            JsonSerializerSettings jsetting = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore };
+            jsetting.Converters.Add(new StringEnumConverter());
+            return jsetting;
+        }
+    }
+   
+
+    #endregion
+}

+ 166 - 0
Executer/DataCheck/Utils/DataCheckRule.cs

@@ -0,0 +1,166 @@
+/* ==============================================================================
+ * 功能描述:数据检查规范
+ * 创 建 者:Garrett
+ * 创建日期:2018/11/7 15:40:23
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using SAGA.DotNetUtils;
+using SAGA.DotNetUtils.NPOI;
+using ServiceRevitLib.Common;
+
+namespace ServiceRevitLib.Utils
+{
+    /// <summary>
+    /// DataCheckRule
+    /// </summary>
+    class DataCheckRule
+    {
+        public static string MCRPath = Path.Combine(AppBaseInfo.DllRunPath, @"DataCheckResource\模型检查结果输出格式-模版.xlsx");
+        /// <summary>
+        /// 获取设备编码检查Cateogry 列表
+        /// </summary>
+        /// <returns></returns>
+        public static List<DCR_CodeCheckCategory> GetCodeCheckCategories()
+        {
+            var list = NPOIHelper
+                .ConvertExcelSheetToModel<DCR_CodeCheckCategory>(MCRPath);
+            return list;
+        }
+
+        /// <summary>
+        /// 获取预定义的连接件类
+        /// </summary>
+        /// <returns></returns>
+        public static List<DCR_Connector> GetPreDefineConnectors()
+        {
+            var list = NPOIHelper
+                .ConvertExcelSheetToModel<DCR_Connector>(MCRPath);
+            return list;
+        }
+
+        /// <summary>
+        /// 获取可识别的管道系统名称
+        /// </summary>
+        /// <returns></returns>
+        public static List<DCR_MEPSystem> GetMepSystems()
+        {
+            var list = NPOIHelper
+                .ConvertExcelSheetToModel<DCR_MEPSystem>(MCRPath);
+            return list;
+        }
+        /// <summary>
+        /// 获取设备关联的系统类型
+        /// </summary>
+        /// <returns></returns>
+        public static List<DCR_EquipReferSystem> GetEquipReferSystems()
+        {
+            var list = NPOIHelper
+                .ConvertExcelSheetToModel<DCR_SystemReferEquip>(MCRPath);
+            List<Tuple<string, string>> tuples = new List<Tuple<string, string>>();
+            //将集合转化为:系统名称-设备名称
+            list.ForEach(t => t.Equips.ForEach(tt => tuples.Add(new Tuple<string, string>(t.SystemName, tt))));
+            //将集合转化为:设备名称-多个系统名称
+            var newList = tuples.GroupBy(t => t.Item2).Select(tt => new DCR_EquipReferSystem()
+            { EquipName = tt.Key, Systems = tt.Select(t => t.Item1).ToList() }).ToList();
+            return newList;
+        }
+    }
+    /// <summary>
+    /// 参考-可识别的系统名称
+    /// </summary>
+    [SheetInfo(SheetName = "参考-可识别的系统名称", RowStartIndex = 0)]
+    public class DCR_MEPSystem
+    {
+        [CellIndex(0)]
+        public string Name { get; set; }
+    }
+    /// <summary>
+    /// 参考-revit分类
+    /// </summary>
+    [SheetInfo(SheetName = "参考-revit分类", RowStartIndex = 0)]
+    public class DCR_CodeCheckCategory
+    {
+        [CellIndex(0)]
+        public string Name { get; set; }
+    }
+    /// <summary>
+    /// 设备类是否有连接件
+    /// </summary>
+    [SheetInfo(SheetName = "参考-连接件对照表", RowStartIndex = 1)]
+    public class DCR_Connector
+    {
+        [CellIndex(4)]
+        public string Name { get; set; }
+
+        [CellIndex(5)]
+        public string Code { get; set; }
+
+        [CellIndex(6)]
+        public string PName { get; set; }
+
+        [CellIndex(7)]
+        public string PCode { get; set; }
+
+        [CellIndex(8)]
+        public string HvacConnector { get; set; }
+
+        [CellIndex(9)]
+        public string PipeConnector { get; set; }
+    }
+    /// <summary>
+    /// 参考-管网与相关设备
+    /// </summary>
+    [SheetInfo(SheetName = "参考-管网及相关设备", RowStartIndex = 3)]
+    public class DCR_SystemReferEquip
+    {
+        [CellIndex(3)]
+        public string SystemName { get; set; }
+        [CellIndex(4)]
+        public string ReferEquipName { get; set; }
+
+        private List<string> m_Equips;
+
+        public List<string> Equips
+        {
+            get
+            {
+                if (m_Equips == null)
+                    m_Equips = ConverToList(ReferEquipName);
+                return m_Equips;
+            }
+        }
+
+        public List<string> ConverToList(string str)
+        {
+            var list = new List<string>();
+            if (str.IsNotNullEmpty())
+            {
+                Regex regex = new Regex(@"^[A-Z]{4}");
+                list = str.Split(new[] { ',', ',' })
+                    .Where(t => Regex.IsMatch(t, $"{RegexConstPattern.IsEquip}"))
+                    .Select(tt => regex.Match(tt).Value).ToList();
+            }
+
+            return list;
+        }
+    }
+    /// <summary>
+    /// 设备关联的系统
+    /// </summary>
+    public class DCR_EquipReferSystem
+    {
+        /// <summary>
+        /// 设备名称
+        /// </summary>
+        public string EquipName { get; set; }
+        /// <summary>
+        /// 系统名称
+        /// </summary>
+        public List<string> Systems { get; set; }
+    }
+}

+ 23 - 0
Executer/DataCheck/app.config

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="NPOI" publicKeyToken="0df73ec7942b34e1" culture="neutral"/>
+        <bindingRedirect oldVersion="0.0.0.0-2.3.0.0" newVersion="2.3.0.0"/>
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="NPOI.OOXML" publicKeyToken="0df73ec7942b34e1" culture="neutral"/>
+        <bindingRedirect oldVersion="0.0.0.0-2.3.0.0" newVersion="2.3.0.0"/>
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="ICSharpCode.SharpZipLib" publicKeyToken="1b03e6acf1164f73" culture="neutral"/>
+        <bindingRedirect oldVersion="0.0.0.0-1.0.0.999" newVersion="1.0.0.999"/>
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
+        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0"/>
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/></startup></configuration>

+ 6 - 0
Executer/DataCheck/packages.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Newtonsoft.Json" version="11.0.1" targetFramework="net461" />
+  <package id="NPOI" version="2.2.1" targetFramework="net461" />
+  <package id="SharpZipLib" version="0.86.0" targetFramework="net461" />
+</packages>

+ 49 - 0
Executer/DataExport/JBIM.sln

@@ -0,0 +1,49 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.3
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JBIM", "JBIM\JBIM.csproj", "{A6A90BFE-126D-4499-860A-F0E2C40EBB23}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitExport", "RevitExport\RevitExport.csproj", "{825B43F4-1F7B-44AC-9BD4-501DE9422D32}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitToJBim", "RevitToJBim\RevitToJBim.csproj", "{F83397D2-C35A-4F5C-8DAF-E9DE1E2D2AD5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExportStart", "ExportStart\ExportStart.csproj", "{003C65AE-6802-4142-97FE-611C23E3676D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceDataCheck", "ServiceDataCheck\ServiceDataCheck.csproj", "{7B748B09-DC20-4406-85A3-101E7833F8CE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{A6A90BFE-126D-4499-860A-F0E2C40EBB23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A6A90BFE-126D-4499-860A-F0E2C40EBB23}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A6A90BFE-126D-4499-860A-F0E2C40EBB23}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A6A90BFE-126D-4499-860A-F0E2C40EBB23}.Release|Any CPU.Build.0 = Release|Any CPU
+		{825B43F4-1F7B-44AC-9BD4-501DE9422D32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{825B43F4-1F7B-44AC-9BD4-501DE9422D32}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{825B43F4-1F7B-44AC-9BD4-501DE9422D32}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{825B43F4-1F7B-44AC-9BD4-501DE9422D32}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F83397D2-C35A-4F5C-8DAF-E9DE1E2D2AD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F83397D2-C35A-4F5C-8DAF-E9DE1E2D2AD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F83397D2-C35A-4F5C-8DAF-E9DE1E2D2AD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F83397D2-C35A-4F5C-8DAF-E9DE1E2D2AD5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{003C65AE-6802-4142-97FE-611C23E3676D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{003C65AE-6802-4142-97FE-611C23E3676D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{003C65AE-6802-4142-97FE-611C23E3676D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{003C65AE-6802-4142-97FE-611C23E3676D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7B748B09-DC20-4406-85A3-101E7833F8CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7B748B09-DC20-4406-85A3-101E7833F8CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7B748B09-DC20-4406-85A3-101E7833F8CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7B748B09-DC20-4406-85A3-101E7833F8CE}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {6ADA978E-6CF2-4C12-AEAE-D090120BEBE2}
+	EndGlobalSection
+EndGlobal

+ 96 - 0
Executer/DataExport/JBIM/BimDocument.cs

@@ -0,0 +1,96 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:BimDocument
+ * 作者:xulisong
+ * 创建时间: 2019/6/13 11:01:06
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JBIM
+{
+    /// <summary>
+    /// Bim文件类信息
+    /// </summary>
+    public class BimDocument
+    {
+        public BimDocument()
+        {
+            BimObjects = new ReadOnlyCollection<BimObject>(m_InnerObjects = new List<BimObject>());
+        }
+
+        private List<BimObject> m_InnerObjects;
+        private Dictionary<BimId, BimObject> m_IndexObjects = new Dictionary<BimId, BimObject>();
+        /// <summary>
+        /// 关联所有对象
+        /// </summary>
+        public ReadOnlyCollection<BimObject> BimObjects { get; private set; }
+
+        /// <summary>
+        /// 当前索引信息
+        /// </summary>
+        private long CurrentIndex { get; set; } = 10000;
+        internal BimId GenerateId()
+        {
+            return new BimId((++CurrentIndex).ToString());
+        }
+
+        public BimObject NewObject(BimObject originObject)
+        {
+            if (originObject.Id != null)
+            {
+                return originObject;
+            }
+            originObject.Id = GenerateId();
+            AddObject(originObject);
+            return originObject;
+        }
+        /// <summary>
+        /// 增加预定义对象
+        /// </summary>
+        /// <param name="originObject"></param>
+        /// <returns></returns>
+        public bool AddPredefinedObject(BimObject originObject)
+        {
+            if (originObject.Id == null)
+            {
+                return false;
+            }
+
+            if (m_IndexObjects.TryGetValue(originObject.Id, out BimObject oldObject))
+            {
+                //移除信息
+                if (oldObject != null)
+                {
+                    m_InnerObjects.Remove(oldObject);
+                }               
+                m_IndexObjects[originObject.Id] = originObject;
+            }
+            else
+            {
+                AddObject(originObject);
+            }
+            return true;
+        }
+        private void AddObject(BimObject originObject)
+        {
+            this.m_InnerObjects.Add(originObject);
+            m_IndexObjects[originObject.Id] = originObject;
+        }
+
+        public BimObject GetBimObject(BimId id)
+        {
+            //查询可优化,简单的二分查找
+            if (m_IndexObjects.TryGetValue(id, out BimObject result))
+            {
+                return result;
+            }
+            return null;
+        }
+    }
+}

+ 74 - 0
Executer/DataExport/JBIM/BimId.cs

@@ -0,0 +1,74 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:BimId
+ * 作者:xulisong
+ * 创建时间: 2019/6/13 9:57:38
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JBIM
+{
+    /*
+     * 定义BimId类,初始化相关ID类型的引用
+     * 引入该类,是为了方便在Id这一类型上的扩展,毕竟它和普通的基本类型有所不同
+     */
+    /// <summary>
+    /// bimId类
+    /// </summary>
+    public class BimId
+    {
+        public BimId(string id)
+        {
+            this.Id = id;
+        }
+        /// <summary>
+        /// Id值
+        /// </summary>
+        public string Id { get; private set; }
+
+        public override string ToString()
+        {
+            return Id?.ToString() ?? string.Empty;
+        }
+        public override bool Equals(object obj)
+        {
+            if (obj is BimId inputId)
+            {
+                return Id == inputId.Id;
+
+            }
+            return false;
+        }
+        public override int GetHashCode()
+        {
+            if (string.IsNullOrWhiteSpace(Id))
+            {
+                return 0;
+            }
+
+            return Id.GetHashCode();
+        }
+        public static bool operator ==(BimId a, BimId b)
+        {
+            if ((object)a == null)
+            {
+                return (object)b == null;
+            }
+            return a.Equals(b);
+        }
+        public static bool operator !=(BimId a, BimId b)
+        {
+            if ((object)a == null)
+            {
+                return ((object)b != null);
+            }
+            return !a.Equals(b);
+        }
+
+    }
+}

+ 51 - 0
Executer/DataExport/JBIM/BimObject.cs

@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:BimObject
+ * 作者:xulisong
+ * 创建时间: 2019/6/12 10:36:34
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using JBIM.Common;
+using JBIM.Definition;
+
+namespace JBIM
+{
+    [TypeDefiniton(TypeDefinition.BimObject)]
+    public class BimObject
+    {
+        public BimObject()
+        {
+            ElementType = GetElementType();
+        }
+        public BimId Id { get; internal set; }
+        public string ElementType { get; protected set; }
+        /// <summary>
+        /// 附加信息,预留
+        /// </summary>
+        public string Tag { get; set; }
+        /// <summary>
+        /// 获取类型Type
+        /// </summary>
+        /// <returns></returns>
+        protected string GetElementType()
+        {
+            var attributes = this.GetType().GetCustomAttributes(typeof(TypeDefinitonAttribute), true);
+            string result = null;
+            if (attributes.Any())
+            {
+                result = (attributes[0] as TypeDefinitonAttribute)?.GetTypeDefiniton();
+            }
+
+            if (string.IsNullOrEmpty(result))
+            {
+                result = TypeDefinitonUtil.GetTypeDefiniton(TypeDefinition.BimObject);
+            }
+            return result;
+        }
+    }
+}

+ 68 - 0
Executer/DataExport/JBIM/Common/BimObjectUtil.cs

@@ -0,0 +1,68 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:BimObjectUtil
+ * 作者:xulisong
+ * 创建时间: 2019/6/18 15:13:11
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JBIM.Common
+{
+    public static class BimObjectUtil
+    {
+        public static void AcceptRelation<T>(BimObject bimObject, string property,T value)
+        {
+            var propertyInfo=ParseProperty(bimObject, property);
+            if (propertyInfo != null)
+            {
+                if (propertyInfo.PropertyType.IsInstanceOfType(value))
+                {
+                    propertyInfo.SetValue(bimObject, value);
+                }
+            }
+        }
+        /// <summary>
+        /// 增加单关联信息
+        /// </summary>
+        /// <param name="bimObject"></param>
+        /// <param name="property"></param>
+        /// <param name="value"></param>
+        public static void AcceptRelation(BimObject bimObject, string property, BimId value)
+        {
+            AcceptRelation<BimId>(bimObject, property, value);
+        }
+        /// <summary>
+        /// 增加一对多关联信息
+        /// </summary>
+        /// <param name="bimObject"></param>
+        /// <param name="property"></param>
+        /// <param name="value"></param>
+        public static void AcceptRelations(BimObject bimObject, string property,List<BimId> value)
+        {
+            AcceptRelation<List<BimId>>(bimObject, property, value);
+        }
+        private static PropertyInfo ParseProperty(BimObject bimObject,string pName)
+        {
+            var type = bimObject.GetType();
+            string propertyName = pName;
+            var key = type.FullName + "_" + propertyName;
+            var propertyInfo = PropertyCache.GetProperty(key);
+            if (propertyInfo == null)
+            {
+                //缓存解析出来的属性元数据,以便提高解析速度
+                propertyInfo = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
+                if(propertyInfo!=null)
+                {
+                    PropertyCache.SetProperty(key, propertyInfo);
+                }
+            }
+            return propertyInfo;
+        }
+    }
+}

+ 37 - 0
Executer/DataExport/JBIM/Common/EnumExtensions.cs

@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:EnumExtensions
+ * 作者:xulisong
+ * 创建时间: 2019/6/17 10:43:13
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System.ComponentModel;
+using System.Reflection;
+
+namespace JBIM.Common
+{
+    public static class EnumExtensions
+    {
+        /// <summary>
+        /// 获取指定枚举类型的描述值
+        /// </summary>
+        /// <typeparam name="T">枚举类型</typeparam>
+        /// <returns></returns>
+        public static string GetDescription<T>(this T t) where T : struct
+        {
+            string description = t.ToString();
+            FieldInfo fieldInfo = t.GetType().GetField(description);
+            object[] attributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
+            if (attributes.Length > 0)
+            {
+                DescriptionAttribute info = attributes[0] as DescriptionAttribute;
+                if (info != null)
+                {
+                    description = info.Description;
+                }
+
+            }
+            return description;
+        }
+    }
+}

+ 37 - 0
Executer/DataExport/JBIM/Common/PropertyCache.cs

@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:PropertyCache
+ * 作者:xulisong
+ * 创建时间: 2019/6/17 10:04:51
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace JBIM.Common
+{
+    public static class PropertyCache
+    {
+        private static readonly Dictionary<string, PropertyInfo> m_CacheProperties = new Dictionary<string, PropertyInfo>();
+
+        /// <summary>
+        /// 设置指定键值的属性
+        /// </summary>
+        /// <param name="key"></param>
+        /// <param name="propertyInfo"></param>
+        public static void SetProperty(string key, PropertyInfo propertyInfo)
+        {
+            m_CacheProperties[key] = propertyInfo;
+        }
+        /// <summary>
+        /// 获取指定键值的属性
+        /// </summary>
+        /// <param name="key"></param>
+        /// <returns></returns>
+        public static PropertyInfo GetProperty(string key)
+        {
+            m_CacheProperties.TryGetValue(key, out PropertyInfo result);
+            return result;
+        }
+    }
+}

+ 34 - 0
Executer/DataExport/JBIM/Common/TypeDefinitonAttribute.cs

@@ -0,0 +1,34 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:TypeDefinitonAttribute
+ * 作者:xulisong
+ * 创建时间: 2019/6/12 11:26:04
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using JBIM.Definition;
+
+namespace JBIM.Common
+{
+    [AttributeUsage(AttributeTargets.Class)]
+    public class TypeDefinitonAttribute:Attribute
+    {
+        /*
+         * 由于可能扩展相关TypeDefiniton的生成方式,所以以方法形式返回需要值
+         */
+        private TypeDefinition m_TypeDefintion;
+        public TypeDefinitonAttribute(TypeDefinition typeDefinition)
+        {
+            m_TypeDefintion = typeDefinition;
+        }
+
+        public virtual string GetTypeDefiniton()
+        {
+            return TypeDefinitonUtil.GetTypeDefiniton(m_TypeDefintion);
+        }
+    }
+}

+ 25 - 0
Executer/DataExport/JBIM/Common/TypeDefinitonUtil.cs

@@ -0,0 +1,25 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:TypeDefinitonUtil
+ * 作者:xulisong
+ * 创建时间: 2019/6/13 11:31:46
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using JBIM.Definition;
+
+namespace JBIM.Common
+{
+    public static class TypeDefinitonUtil
+    {
+        public static string GetTypeDefiniton(TypeDefinition typeDefinition)
+        {
+            return typeDefinition.ToString();
+        }
+
+    }
+}

+ 0 - 0
Executer/DataExport/JBIM/Component/BoundarySegment.cs


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است