Browse Source

socket模块联调

DOVER-GLOBAL\11047086 7 months ago
parent
commit
f6be671b5f

+ 1 - 1
Edge.Core/Edge.Core.csproj

@@ -23,7 +23,7 @@
     <PackageReference Include="MQTTnet" Version="4.3.7.1207" />
     <PackageReference Include="MQTTnet.Extensions.ManagedClient" Version="4.3.7.1207" />
     <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
-    <PackageReference Include="Newtonsoft.Json.Schema" Version="4.0.1" />
+    <PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.14" />
     <PackageReference Include="NLog" Version="5.3.4" />
     <PackageReference Include="RestSharp" Version="112.1.0" />
     <PackageReference Include="System.IO.Ports" Version="8.0.0" />

+ 153 - 0
Edge.Core/ExtentionMethod.cs

@@ -0,0 +1,153 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Edge.Core
+{
+    public static class ExtentionMethod
+    {
+        /// <summary>
+        /// Extract the localized content string from source, the source should follow the format-> lang-zh-cn:稳Dart加油机lang-en-us:WayneDartPump
+        /// </summary>
+        /// <param name="source">should follow the format-> lang-zh-cn:稳Dart加油机lang-en-us:WayneDartPumplang-xx:xContent</param>
+        /// <param name="language">like-> en-us, zh-cn, or en, zh</param>
+        /// <returns>if target language is not searched from source, then content with 'en' locale will be returned, if 'en' locale is not searched, content with 'zh-cn' locale will be returned original, otherwise source will be returned</returns>
+        public static string LocalizedContent(this string source, string language)
+        {
+            if (string.IsNullOrEmpty(source)) return source;
+            //if (string.IsNullOrEmpty(language)) return source;
+            //var langDeclareRegexStr = @"(lang-\w\w-\w\w\:).+?((?=lang-\w\w-\w\w\:)|(?=$))";
+            var allLangDeclareRegexStr = @"(lang-\w\w(-\w\w)?\:).+?((?=lang-\w\w(-\w\w)?\:)|(?=$))";
+            var allLangMatches = Regex.Matches(source, allLangDeclareRegexStr).Cast<Match>();
+            foreach (var langMatch in allLangMatches)
+            {
+                var targetLangPrefix = "^lang-" + language + @"(-\w\w)?\:";
+                var m = Regex.Match(langMatch.Value, targetLangPrefix, RegexOptions.IgnoreCase);
+                if (m.Success)
+                    return langMatch.Value.Substring(m.Length);
+            }
+
+            var default_match =
+                allLangMatches.FirstOrDefault(m =>
+                    m.Value.Split(':')[0].Contains("en", StringComparison.OrdinalIgnoreCase));
+            if (default_match == null)
+                default_match = allLangMatches.FirstOrDefault(m =>
+                    m.Value.Split(':')[0].Contains("zh-cn", StringComparison.OrdinalIgnoreCase));
+            return default_match?.Value?.Substring(default_match.Value.Split(':')[0].Length + 1) ?? source;
+        }
+
+        /// <summary>
+        /// Extract the localized content string from the json schema source.
+        ///     the multi-language text in json schema is like-> "title": "lang-zh-cn:停止位lang-en-us:StopBits"
+        /// </summary>
+        /// <param name="jsonSchemaSource"></param>
+        /// <param name="language">like-> en-us, zh-cn, or en, zh</param>
+        /// <returns></returns>
+        public static string LocalizedJsonSchema(this string jsonSchemaSource, string language)
+        {
+            if (string.IsNullOrEmpty(jsonSchemaSource)) return jsonSchemaSource;
+            //if (string.IsNullOrEmpty(language)) return jsonSchemaSource;
+            // sample:   "title": "lang-zh-cn:停止位lang-en-us:StopBits"
+            var targetContentRegexStr = @"(?<=\""(title|infoText)\""\s*?\:\s*?\"").+?((?=\"")|(?=$))";
+            var matches = Regex.Matches(jsonSchemaSource, targetContentRegexStr, RegexOptions.Multiline | RegexOptions.IgnoreCase).Cast<Match>();
+
+            foreach (var ma in matches)
+            {
+                jsonSchemaSource = jsonSchemaSource.Replace(ma.Value, ma.Value.LocalizedContent(language));
+            }
+
+            //var allInfoTextContentRegexStr = @"(?<=\""infoText\""\s*?\:\s*?\"").+?((?=\"")|(?=$))";
+            //var allInfoTextContentMatches = Regex.Matches(jsonSchemaSource, allInfoTextContentRegexStr, RegexOptions.Multiline | RegexOptions.IgnoreCase).Cast<Match>();
+
+            //foreach (var infoTextNodeContentMatch in allInfoTextContentMatches)
+            //{
+            //    jsonSchemaSource =
+            //        jsonSchemaSource.Replace(infoTextNodeContentMatch.Value,
+            //            infoTextNodeContentMatch.Value.LocalizedContent(language));
+            //}
+
+            return jsonSchemaSource;
+        }
+
+        /// <summary>
+        /// Search the target byte list in src.
+        /// </summary>
+        /// <param name="src"></param>
+        /// <param name="target"></param>
+        /// <returns>-1 indicates can not find target in src, otherwise, return the index in src, 0 based.</returns>
+        public static int IndexOfSubList(this List<byte> src, List<byte> target)
+        {
+            if (src.Count < target.Count) return -1;
+            int everFound = 0;
+            int srcIndex = 0;
+            int targetIndex = 0;
+            for (int i = 0; i < src.Count; i++)
+            {
+                //if (srcIndex == src.Count - 1)
+                //{
+                //    if (everFound == target.Count) return srcIndex - target.Count + 1;
+                //    else return -1;
+                //}
+
+                if (everFound == target.Count) return srcIndex - target.Count;
+                if (src[srcIndex] == target[targetIndex])
+                {
+                    everFound++;
+                    srcIndex++;
+                    targetIndex++;
+                }
+                else
+                {
+                    if (everFound > 0)
+                    { targetIndex = 0; everFound = 0; }
+                    else
+                    {
+                        srcIndex++;
+                    }
+                }
+            }
+
+            if (everFound == target.Count) return srcIndex - target.Count;
+            return -1;
+        }
+
+        /// <summary>
+        /// create a custom logger if it does not exists, otherwise get the logger.
+        /// This is only for NLog implementation.
+        /// </summary>
+        /// <param name="loggerFactory"></param>
+        /// <param name="loggerFileName">custom logger file name will be created or get.</param>
+        /// <returns></returns>
+        public static ILogger CreateOrGetCustomLogger(this ILoggerFactory loggerFactory, string loggerFileName, LogLevel logLevel)
+        {
+            if (string.IsNullOrEmpty(loggerFileName)) throw new ArgumentException("loggerFileName must not be null or empty");
+            ILogger logger = null;
+            switch (logLevel)
+            {
+                case LogLevel.Trace:
+                    logger = loggerFactory.CreateLogger("DynamicPrivate_Trace_" + loggerFileName);
+                    break;
+                case LogLevel.Debug:
+                    logger = loggerFactory.CreateLogger("DynamicPrivate_Debug_" + loggerFileName);
+                    break;
+                case LogLevel.Information:
+                    logger = loggerFactory.CreateLogger("DynamicPrivate_Info_" + loggerFileName);
+                    break;
+                case LogLevel.Warning:
+                    logger = loggerFactory.CreateLogger("DynamicPrivate_Warn_" + loggerFileName);
+                    break;
+                case LogLevel.Error:
+                    logger = loggerFactory.CreateLogger("DynamicPrivate_Error_" + loggerFileName);
+                    break;
+                case LogLevel.Critical:
+                    logger = loggerFactory.CreateLogger("DynamicPrivate_Fatal_" + loggerFileName);
+                    break;
+            }
+
+            return logger;
+        }
+    }
+}

+ 1 - 1
Edge.Core/Processor/Communicator/TcpClientShortConnCommunicator.cs

@@ -103,7 +103,7 @@ namespace Edge.Core.Processor.Communicator
                     try
                     {
                         eventArg.Data = this.messageCutter.Message;
-                        eventArg.Message = this.parser.Deserialize(this.messageCutter.Message.ToArray()) as T;
+                        //eventArg.Message = this.parser.Deserialize(this.messageCutter.Message.ToArray()) as T;
                         if (logger.IsDebugEnabled)
                             logger.Debug("      Parsed: " + eventArg.Message.ToLogString());
                     }

+ 88 - 0
Edge.Core/Processor/Communicator/TcpServer.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Sockets;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Edge.Core.Processor.Communicator
+{
+    public class TcpServer
+    {
+        private TcpListener _listener;
+        private string _localIp;
+        private int _port;
+
+        public TcpServer(string localIp, int port)
+        {
+            _localIp = localIp;
+            _port = port;
+            _listener = new TcpListener(IPAddress.Parse(_localIp), _port);
+        }
+
+        public async Task StartAsync()
+        {
+            _listener.Start();
+            Console.WriteLine("Server started. Listening for connections...");
+
+            while (true)
+            {
+                // 异步等待客户端连接
+                TcpClient client = await _listener.AcceptTcpClientAsync();
+                IPEndPoint clientEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;
+                string clientIp = clientEndPoint.Address.ToString();
+                int clientPort = clientEndPoint.Port;
+                Console.WriteLine($"Client connected: {clientIp}:{clientPort}");
+
+                // 处理客户端连接
+                Task.Run(() => HandleClient(client, clientIp, clientPort));
+            }
+        }
+
+        private async Task HandleClient(TcpClient client, string clientIp, int clientPort)
+        {
+            using (client)
+            {
+                NetworkStream stream = client.GetStream();
+                byte[] buffer = new byte[1024];
+
+                while (true)
+                {
+                    try
+                    {
+                        // 从客户端读取数据
+                        int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
+                        if (bytesRead == 0)
+                        {
+                            // 客户端断开连接
+                            break;
+                        }
+
+                        // 将接收到的数据转换为字符串
+                        string data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
+                        Console.WriteLine($"Received from {clientIp}:{clientPort}: {data}");
+
+                        // 回应客户端
+                        string response = "Message received: " + data;
+                        byte[] responseBytes = Encoding.UTF8.GetBytes(response);
+                        await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine($"Error handling client {clientIp}:{clientPort}: {ex.Message}");
+                        break;
+                    }
+                }
+
+                Console.WriteLine($"Client disconnected: {clientIp}:{clientPort}");
+            }
+        }
+
+        public void Stop()
+        {
+            _listener.Stop();
+            Console.WriteLine("Server stopped.");
+        }
+    }
+}

+ 1 - 1
Edge.Core/Processor/Communicator/TcpServerCommunicator.cs

@@ -102,7 +102,7 @@ namespace Edge.Core.Processor.Communicator
                     try
                     {
                         eventArg.Data = this.messageCutter.Message;
-                        eventArg.Message = this.parser.Deserialize(this.messageCutter.Message.ToArray()) as T;
+                        //eventArg.Message = this.parser.Deserialize(this.messageCutter.Message.ToArray()) as T;
                         if (logger.IsEnabled(LogLevel.Debug))
                             this.logger.LogDebug("      Parsed: " + eventArg.Message.ToLogString());
                     }

+ 548 - 0
Edge.Core/Processor/Dispatcher/DefaultDispatcher.cs

@@ -0,0 +1,548 @@
+using AutoMapper;
+using Edge.Core.Configuration;
+using Edge.Core.Database.Configuration.Models;
+using Edge.Core.Processor.Communicator;
+using Edge.Core.Processor.Dispatcher.Attributes;
+using Edge.Core.UniversalApi;
+using Edge.Core.UniversalApi.CommunicationProvider;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Newtonsoft.Json.Schema;
+using Newtonsoft.Json.Schema.Generation;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace Edge.Core.Processor.Dispatcher
+{
+    [UniversalApi(Name = DefaultDispatcher.OnProcessorsLifeCycleChangedEventApiName,
+        EventDataType = typeof(OnProcessorsLifeCycleChangedEventArg),
+        Description = "When life cycle of processors are changed, an event will fired with details for each processor.")]
+    [UniversalApi(Name = GenericAlarm.UniversalApiEventName, EventDataType = typeof(object), Description = "Fire GenericAlarm which mostly used in Alarm UI Bar for attracting users.")]
+    [MetaPartsDescriptor("DefaultDispatcher", "Processors' life cycle manager.",
+        new[] { "Managment" },
+        IsSystemInternalComponent = true)]
+    public partial class DefaultDispatcher : IAppProcessor
+    {
+        public const string OnProcessorsLifeCycleChangedEventApiName = "OnProcessorsLifeCycleChanged";
+        private List<OnProcessorsLifeCycleChangedEventArg> historyProcessorsLifeCycleChangedEvents
+            = new List<OnProcessorsLifeCycleChangedEventArg>();
+        public event EventHandler<OnProcessorsInstantiatedEventArg> OnProcessorInstantiated;
+
+        /// <summary>
+        /// latest instantiated processor result.
+        /// </summary>
+        private IEnumerable<ProcessorInstanceOperatingResult> currentProcessorInstantiatedOperatingResults;
+        //public static EventHandler OnRequestDispatch;
+        protected IServiceProvider services;
+        protected static ILogger mainLogger = NullLogger.Instance;
+
+        public string MetaConfigName { get; set; } = "ProcessorsDispatcher";
+        public static string DefaultClientAcceptLanguage = "zh-cn";
+        static DefaultDispatcher()
+        {
+            // replace with your license key, https://www.newtonsoft.com/jsonschema
+            string licenseKey = "4278-fsXeHk11Z1h23Ki2z21y8tDMv43+eMW7Gcnv6caaGWz6w8Q4xrsg/Ow/moZc6GrkgjCaiq33yzr/meweRwNrPHsfqTc1rgpJu385YKKqMbJ5UKUDV1csm5ZwpMBIc1JJDbQwVZuDqUyOFqLZ31uk+10j9i8uMTPGEzLI729edmx7IklkIjo0Mjc4LCJFeHBpcnlEYXRlIjoiMjAyMS0wNy0wNFQwNjoxMjozMC43Mzc1NTE1WiIsIlR5cGUiOiJKc29uU2NoZW1hQnVzaW5lc3MifQ==";
+            License.RegisterLicense(licenseKey);
+            //AppDomain.CurrentDomain.TypeResolve += (s, args) =>
+            //{
+            //    var type = ObjectInstanceCreator.DefaultSearchLocalAssemblyFileTypeResolver(args.Name);
+            //    return type?.Assembly;
+            //};
+            //AppDomain.CurrentDomain.AssemblyResolve += (s, args) =>
+            //{
+            //    return ObjectInstanceCreator.DefaultSearchLocalAssemblyFileAssemblyResolver(args.Name);
+            //};
+        }
+
+        public DefaultDispatcher(IServiceProvider services)
+        {
+            this.services = services;
+            var loggerFactory = services.GetRequiredService<ILoggerFactory>();
+            mainLogger = loggerFactory.CreateLogger("Main");
+            ObjectInstanceCreator.mainLogger = mainLogger;
+            mainLogger.LogInformation("AppDomain.CurrentDomain.CurrentDomainAssemblies: " +
+               ObjectInstanceCreator.CurrentDomainAssemblies?.Select(ass => ass.FullName + "      " + (!ass.IsDynamic ? ass.Location ?? "" : "")).OrderBy(o => o)
+                   .Aggregate(Environment.NewLine, (acc, n) => acc + n + Environment.NewLine) ?? "");
+            //route this special event into this processor rather than from different processors to form an unified api entrance.
+            //this.services.GetRequiredService<UniversalApiHub>().OnUniversalGenericAlarmEventFired += async (s, a) =>
+            //{
+            //    await this.services.GetRequiredService<UniversalApiHub>().FireEvent(this,
+            //        GenericAlarm.UniversalApiEventName, new
+            //        {
+            //            Title = a.GenericAlarm.Title.LocalizedContent(DefaultClientAcceptLanguage),
+            //            Category = a.GenericAlarm.Category?.LocalizedContent(DefaultClientAcceptLanguage),
+            //            SubCategory = a.GenericAlarm.SubCategory?.LocalizedContent(DefaultClientAcceptLanguage),
+            //            Detail = a.GenericAlarm.Detail?.LocalizedContent(DefaultClientAcceptLanguage),
+            //            a.GenericAlarm.Severity,
+            //            a.PersistId
+            //        });
+            //};
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="reason"></param>
+        /// <returns></returns>
+        public virtual async Task<IEnumerable<ProcessorInstanceOperatingResult>> CreateProcessorsAsync(string reason, bool enableSafeBoot = false)
+        {
+            var processorLoader = this.services.GetRequiredService<IProcessorLoader>();
+            var defaultDispatcherProcessorInstanceOperatingResult = new ProcessorInstanceOperatingResult()
+            {
+                Succeed = true,
+                ProcessorInstance = this,
+                //for this special AppProcessor as it's included in Edge.Core, so both version are the same
+                HostVersion = Assembly.GetAssembly(this.GetType()).GetName().Version.ToString(),
+                CoreVersion = Assembly.GetAssembly(this.GetType()).GetName().Version.ToString(),
+            };
+            if (enableSafeBoot)
+                this.currentProcessorInstantiatedOperatingResults = new[] { defaultDispatcherProcessorInstanceOperatingResult };
+            else
+                this.currentProcessorInstantiatedOperatingResults =
+                    new[] { defaultDispatcherProcessorInstanceOperatingResult }.Concat(processorLoader.CreateAll()).ToList();
+
+            this.OnProcessorInstantiated?.Invoke(this, new OnProcessorsInstantiatedEventArg(this.currentProcessorInstantiatedOperatingResults));
+            var createEvtArg = new OnProcessorsLifeCycleChangedEventArg(
+                this.currentProcessorInstantiatedOperatingResults.Select(i => ProcessorLifeCycleOperationResult.From(i)).ToList(),
+                "ProcessorsInstantiate",
+                reason);
+            this.historyProcessorsLifeCycleChangedEvents.Add(createEvtArg);
+            return this.currentProcessorInstantiatedOperatingResults;
+        }
+
+        public virtual async Task<IEnumerable<ProcessorInstanceOperatingResult>> StartProcessorsAsync(
+            IEnumerable<IProcessor> processorInstances, string reason)
+        {
+            //App will call Init(...) before Start()
+            var initOrStartResults = new List<ProcessorInstanceOperatingResult>();
+
+            mainLogger.LogInformation("==============Start Processors (total: " + processorInstances.Count() + ")==============");
+            Console.WriteLine();
+            Console.WriteLine("==============Start Processors (total: " + processorInstances.Count() + ")==============");
+
+            var pendingForStartInstances = processorInstances.ToList();
+
+            // call App.Init(...), and only succeed ones will call its Start() later.
+            processorInstances.OfType<IAppProcessor>().ToList().ForEach(app =>
+            {
+                try
+                {
+                    app.Init(processorInstances);
+                }
+                catch (Exception eee)
+                {
+                    //remove it for avoid call Start()
+                    pendingForStartInstances.Remove(app);
+                    initOrStartResults.Add(new ProcessorInstanceOperatingResult()
+                    {
+                        //WhatThisProcessorUsedFor = p.ProcessorDescriptor().DeviceHandlerOrApp.GetType().GetCustomAttributes<MetaPartsDescriptor>()?.FirstOrDefault()?.Description,
+                        ProcessorInstance = app,
+                        Succeed = false,
+                        FailedReason = "Call App.Init(...) exceptioned: " + eee.ToString(),
+                        //Description = $"Ordinary start a processor but failed with an unexpected fatal error",
+                    });
+                    mainLogger.LogError("Initing [" + (app.MetaConfigName ?? "") + "] failed and will skip its Start: " + eee.ToString());
+                    Console.BackgroundColor = ConsoleColor.Red;
+                    Console.ForegroundColor = ConsoleColor.Black;
+                    Console.WriteLine("Initing [" + (app.MetaConfigName ?? "") + "] failed: " + Environment.NewLine + "   " + eee.ToString().Substring(0, 70) + "...");
+                    Console.ResetColor();
+                }
+            });
+            for (int i = 0; i < pendingForStartInstances.Count(); i++)
+            {
+                var p = pendingForStartInstances.ElementAt(i);
+                try
+                {
+                    mainLogger.LogInformation("Starting [" + (p.MetaConfigName ?? "") + "]: ");
+                    Console.WriteLine("Starting [" + (p.MetaConfigName ?? "") + "]: ");
+                    bool r = await p.Start();
+                    if (r)
+                    {
+                        initOrStartResults.Add(new ProcessorInstanceOperatingResult()
+                        {
+                            //WhatThisProcessorUsedFor = p.ProcessorDescriptor().DeviceHandlerOrApp.GetType().GetCustomAttributes<MetaPartsDescriptor>()?.FirstOrDefault()?.Description,
+                            ProcessorInstance = p,
+                            Succeed = true,
+                            //Description = $"Ordinary start a processor and succeed.",
+                        });
+                        mainLogger.LogInformation("   Started");
+                        Console.WriteLine("   Started");
+                    }
+                    else
+                    {
+                        initOrStartResults.Add(new ProcessorInstanceOperatingResult()
+                        {
+                            //WhatThisProcessorUsedFor = p.ProcessorDescriptor().DeviceHandlerOrApp.GetType().GetCustomAttributes<MetaPartsDescriptor>()?.FirstOrDefault()?.Description,
+                            ProcessorInstance = p,
+                            Succeed = false,
+                            //Description = $"Ordinary start a processor but failed with a graceful reason",
+                        });
+                        mainLogger.LogInformation("   Failed for starting");
+                        Console.BackgroundColor = ConsoleColor.Red;
+                        Console.ForegroundColor = ConsoleColor.Black;
+                        Console.WriteLine("   !!!Failed for starting!!!");
+                        Console.ResetColor();
+                    }
+                }
+                catch (Exception eee)
+                {
+                    initOrStartResults.Add(new ProcessorInstanceOperatingResult()
+                    {
+                        //WhatThisProcessorUsedFor = p.ProcessorDescriptor().DeviceHandlerOrApp.GetType().GetCustomAttributes<MetaPartsDescriptor>()?.FirstOrDefault()?.Description,
+                        ProcessorInstance = p,
+                        Succeed = false,
+                        FailedReason = eee.ToString(),
+                        //Description = $"Ordinary start a processor but failed with an unexpected fatal error",
+                    });
+                    mainLogger.LogError(" - Failed for start: [" + p.MetaConfigName + "]" + Environment.NewLine + "   " + eee.ToString());
+                    Console.BackgroundColor = ConsoleColor.Red;
+                    Console.ForegroundColor = ConsoleColor.Black;
+                    Console.WriteLine(" - Failed for start: [" + p.MetaConfigName + "]" + Environment.NewLine + "   " + eee.ToString().Substring(0, 70) + "...");
+                    Console.ResetColor();
+                }
+            }
+
+            mainLogger.LogInformation("==============Start Processors End==============\r\n");
+            Console.WriteLine("==============Start Processors End==============\r\n");
+
+            var startEvtArg = new OnProcessorsLifeCycleChangedEventArg(
+                initOrStartResults.Select(i => ProcessorLifeCycleOperationResult.From(i)).ToList(),
+                "ProcessorsStart",
+                reason);
+            //var universalApiHub = this.services.GetRequiredService<UniversalApiHub>();
+            //await universalApiHub.FireEvent(this, DefaultDispatcher.OnProcessorsLifeCycleChangedEventApiName, startEvtArg);
+            this.historyProcessorsLifeCycleChangedEvents.Add(startEvtArg);
+            return initOrStartResults;
+        }
+
+        /// <summary>
+        /// Call Stop() on target processors, and correlated life cycle operation results will be recorded.
+        /// </summary>
+        /// <param name="processors"></param>
+        /// <param name="reason"></param>
+        /// <returns></returns>
+        public virtual async Task<IEnumerable<ProcessorInstanceOperatingResult>> StopProcessorsAsync(
+            IEnumerable<IProcessor> processors, string reason)
+        {
+            if (processors == null || !processors.Any()) return Enumerable.Empty<ProcessorInstanceOperatingResult>();
+
+            var stopResults = new List<ProcessorInstanceOperatingResult>();
+            foreach (var p in processors)
+            {
+                try
+                {
+                    Console.WriteLine("     stopping " + p.MetaConfigName + "..." + " by reason: " + (reason ?? ""));
+                    mainLogger.LogInformation("     stopping " + p.MetaConfigName + " by reason: " + (reason ?? ""));
+                    bool r = await p.Stop();
+                    if (r)
+                    {
+                        stopResults.Add(new ProcessorInstanceOperatingResult()
+                        {
+                            //WhatThisProcessorUsedFor = p.ProcessorDescriptor().DeviceHandlerOrApp.GetType().GetCustomAttributes<MetaPartsDescriptor>()?.FirstOrDefault()?.Description,
+                            //ProcessorMetaConfigName = p.MetaConfigName,
+                            ProcessorInstance = p,
+                            Succeed = true,
+                            //Description = $"Ordinary stop a processor and succeed.",
+                        });
+
+                        Console.WriteLine("         Stopped");
+                        mainLogger.LogInformation("         Stopped");
+                    }
+                    else
+                    {
+                        stopResults.Add(new ProcessorInstanceOperatingResult()
+                        {
+                            //WhatThisProcessorUsedFor = p.ProcessorDescriptor().DeviceHandlerOrApp.GetType().GetCustomAttributes<MetaPartsDescriptor>()?.FirstOrDefault()?.Description,
+                            //ProcessorMetaConfigName = p.MetaConfigName,
+                            ProcessorInstance = p,
+                            Succeed = false,
+                            //Description = $"Ordinary stop a processor but failed with a graceful reason",
+                        });
+                    }
+                }
+                catch (Exception xxxx)
+                {
+                    stopResults.Add(new ProcessorInstanceOperatingResult()
+                    {
+                        //WhatThisProcessorUsedFor = p.ProcessorDescriptor().DeviceHandlerOrApp.GetType().GetCustomAttributes<MetaPartsDescriptor>()?.FirstOrDefault()?.Description,
+                        //ProcessorMetaConfigName = p.MetaConfigName,
+                        Succeed = false,
+                        FailedReason = xxxx.ToString(),
+                        //Description = $"Ordinary stop a processor but failed with an unexpected fatal error",
+                    });
+                    Console.BackgroundColor = ConsoleColor.Red;
+                    Console.ForegroundColor = ConsoleColor.Black;
+                    Console.WriteLine("         stopping " + p.MetaConfigName + " failed.");
+                    Console.ResetColor();
+                    mainLogger.LogInformation("         stopping " + p.MetaConfigName + " failed: "
+                        + Environment.NewLine
+                        + xxxx);
+                }
+            }
+
+            var stopEvtArg = new OnProcessorsLifeCycleChangedEventArg(
+                stopResults.Select(i => ProcessorLifeCycleOperationResult.From(i)).ToList(),
+                "ProcessorsStop",
+                reason);
+            this.historyProcessorsLifeCycleChangedEvents.Add(stopEvtArg);
+            var universalApiHub = this.services.GetRequiredService<UniversalApiHub>();
+            await universalApiHub.FireEvent(this, DefaultDispatcher.OnProcessorsLifeCycleChangedEventApiName,
+                stopEvtArg);
+            return stopResults;
+        }
+
+        [UniversalApi(Description = "Get history datas for Processors' LifeCycle Changed Event")]
+        public Task<List<OnProcessorsLifeCycleChangedEventArg>> GetHistoryProcessorsLifeCycleChangedEvents()
+        {
+            return Task.FromResult(this.historyProcessorsLifeCycleChangedEvents);
+        }
+
+        [UniversalApi]
+        public async Task<ProcessorMetaConfig> UpsertProcessorMetaConfigAsync(ProcessorMetaConfig input)
+        {
+            var accessor = this.services.GetService<IProcessorMetaConfigAccessor>();
+            if (accessor == null) throw new NotSupportedException("Could not find ProcessorMetaConfigAccessor, may current ProcessorLoader does not support the MetaConfig Upsert???");
+            return await accessor.UpsertMetaConfigAsync(input);
+        }
+
+        [UniversalApi(Description = "Get all ProcessorMetaConfigs with endPointFullTypeStr qualified with input parameter, or leave null or empty to get all")]
+        public async Task<IEnumerable<ProcessorMetaConfig>> GetProcessorMetaConfigAsync(string sourceEndpointFullTypeStr)
+        {
+            var accessor = this.services.GetService<IProcessorMetaConfigAccessor>();
+            if (accessor == null) throw new NotSupportedException("Could not find ProcessorMetaConfigAccessor, may current ProcessorLoader does not support the MetaConfig Get???");
+            return await accessor.GetMetaConfigAsync(sourceEndpointFullTypeStr);
+        }
+
+        [UniversalApi(InputParametersExampleJson = "[121]", Description = "Remove a ProcessorMetaConfig and all its MetaPartsConfigs")]
+        public async Task<bool> RemoveProcessorMetaConfigAsync(int metaConfigId)
+        {
+            var accessor = this.services.GetService<IProcessorMetaConfigAccessor>();
+            if (accessor == null) throw new NotSupportedException("Could not find ProcessorMetaConfigAccessor, may current ProcessorLoader does not support the MetaConfig Remove???");
+            return await accessor.RemoveMetaConfigAsync(metaConfigId);
+        }
+
+        [UniversalApi(InputParametersExampleJson = "[\"wayne dart pump configuration 1\"]",
+            Description = "Test by constructing a Processor instance on the air from specified metaConfig, start, test and then stop it, any error will treat as test failed.")]
+        public async Task<bool> TestProcessorMetaConfigAsync(string configName, string[] parameters)
+        {
+            var processorLoader = this.services.GetRequiredService<IProcessorLoader>();
+            IProcessor p = null;
+            try
+            {
+                p = processorLoader.Create(configName);
+                if (p == null) throw new InvalidOperationException($"Test failed on constructing processor.");//: {p.MetaConfigName}");
+
+                var startResult = false;
+                try
+                {
+                    startResult = await p.Start();
+                    if (!startResult)
+                        throw new InvalidOperationException($"Test failed on starting processor.");
+                    await p.Test(parameters);
+                }
+                catch (Exception eee)
+                {
+                    throw;// new InvalidOperationException($"Test failed on pre-starting processor with error: {eee}");
+                }
+            }
+            finally
+            {
+                if (p != null)
+                {
+                    var stopResult = false;
+                    try
+                    {
+                        stopResult = await p.Stop();
+                    }
+                    catch (Exception eee)
+                    {
+                        throw;// new InvalidOperationException($"Test failed on pre-stop processor with error: {eee}");
+                    }
+
+                    if (!stopResult)
+                        throw new InvalidOperationException($"Test failed on stopping processor.");
+                }
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="processorMetaPartsConfigId"></param>
+        /// <returns>the original ParametersJsonArrayStr if no resolve method defined in target meta part type, or updated value by call the resolve method</returns>
+        [UniversalApi]
+        public async Task<string> ResolveProcessorMetaPartsConfigCompatibilityAsync(int processorMetaPartsConfigId)
+        {
+            var accessor = this.services.GetService<IProcessorMetaConfigAccessor>();
+            if (accessor == null) throw new NotSupportedException("Could not find ProcessorMetaConfigAccessor, may current ProcessorLoader does not support the MetaConfig Get???");
+            var allMetaConfigs = await accessor.GetMetaConfigAsync();
+            var targetMetaPartsInfo = allMetaConfigs.SelectMany(mc => mc.Parts,
+                    (metaConfig, metaPartsConfig) => new { metaConfig, metaPartsConfig })
+                .FirstOrDefault(p => p.metaPartsConfig.Id == processorMetaPartsConfigId);
+            if (targetMetaPartsInfo == null) throw new ArgumentException("Could not find processorMetaPartsConfig with id: " + processorMetaPartsConfigId);
+
+            if (targetMetaPartsInfo.metaPartsConfig.TryCallMetaPartsConfigCompatibilityMethodAndUpdate())
+            {
+                //targetMetaPartsInfo.metaConfig.Parts.First(p => p.Id == targetMetaPartsInfo.metaPartsConfig.Id)
+                //    .ParametersJsonArrayStr = reformatParamsStr;
+                //await accessor.UpsertMetaConfigAsync(targetMetaPartsInfo.metaConfig);
+            }
+
+            return targetMetaPartsInfo.metaPartsConfig.ParametersJsonArrayStr;
+        }
+
+        [UniversalApi(Description = "Stop all exist non-system processors, and re-instantiate, re-start them again")]
+        public async Task<IEnumerable<ProcessorLifeCycleOperationResult>> ReloadProcessorsAsync(string reason = "")
+        {
+            try
+            {
+                mainLogger.LogInformation($"Stop Non-System Processors is on requesting by reason: {reason}");
+                Console.BackgroundColor = ConsoleColor.Yellow;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + $"=====>Stop All Processors is on requesting by reason: {reason}");
+                Console.ResetColor();
+                var stopResults = await this.StopProcessorsAsync(
+                    this.currentProcessorInstantiatedOperatingResults.Where(r => r.ProcessorInstance != null)
+                        .Select(r => r.ProcessorInstance).Except(new[] { this }),
+                    reason);
+                mainLogger.LogInformation("     Stop Non-System Processors done successfully");
+                Console.BackgroundColor = ConsoleColor.Green;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "<=====Stop All Processors done successfully");
+                Console.ResetColor();
+                //return stopResults;
+            }
+            catch (Exception exx)
+            {
+                mainLogger.LogError("******Stop Non-System Processors got internal error!\r\n" + exx.ToString());
+                Console.BackgroundColor = ConsoleColor.Red;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "******Stop All Processors got internal error: " + exx.ToString().Substring(0, 70) + "...");
+                Console.ResetColor();
+                throw;
+            }
+
+            try
+            {
+                mainLogger.LogInformation($"Create All Processors is on requesting by reason: {reason}");
+                Console.BackgroundColor = ConsoleColor.Yellow;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + $"=====>Create All Processors is on requesting by reason: {reason}");
+                Console.ResetColor();
+                var createResults = await this.CreateProcessorsAsync(reason);
+
+                mainLogger.LogInformation("     Create All Processors done successfully");
+                Console.BackgroundColor = ConsoleColor.Green;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "<=====Create All Processors done successfully");
+                Console.ResetColor();
+                //return createResults;
+            }
+            catch (Exception exx)
+            {
+                mainLogger.LogError("******Create All Processors got internal error!\r\n" + exx.ToString());
+                Console.BackgroundColor = ConsoleColor.Red;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "******Create All Processors got internal error: " + exx.ToString().Substring(0, 70) + "...");
+                Console.ResetColor();
+                throw;
+            }
+
+            try
+            {
+                mainLogger.LogInformation($"Start All Processors is on requesting by reason: {reason}");
+                Console.BackgroundColor = ConsoleColor.Yellow;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + $"=====>Start All Processors is on requesting by reason: {reason}");
+                Console.ResetColor();
+                var startResults = await this.StartProcessorsAsync(
+                    this.currentProcessorInstantiatedOperatingResults.Where(r => r.Succeed).Select(r => r.ProcessorInstance),
+                    reason);
+
+                mainLogger.LogInformation("     Start All Processors done successfully");
+                Console.BackgroundColor = ConsoleColor.Green;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "<=====Start All Processors done successfully");
+                Console.ResetColor();
+                return startResults.Select(r => ProcessorLifeCycleOperationResult.From(r));
+            }
+            catch (Exception exx)
+            {
+                mainLogger.LogError("******Start All Processors got internal error!\r\n" + exx.ToString());
+                Console.BackgroundColor = ConsoleColor.Red;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "******Start All Processors got internal error: " + exx.ToString().Substring(0, 70) + "...");
+                Console.ResetColor();
+                throw;
+            }
+        }
+
+
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="apiType">localmqtt, remotemqtt, webapi</param>
+        /// <param name="tags"></param>
+        /// <returns></returns>
+        [UniversalApi(InputParametersExampleJson = "[\"localMqtt\",[\"Pump\",\"ATG\"]]")]
+        public async Task<IEnumerable<UniversalApiInfoDoc>> ShowMeApi(string apiType, string[] tags)
+        {
+            var communicationProvider =
+                this.services.GetService<UniversalApiHub>()?.CommunicationProviders?.Where(p => p.GetType().Name.Contains(apiType, StringComparison.OrdinalIgnoreCase))?.FirstOrDefault();
+            if (communicationProvider == null)
+                return Enumerable.Empty<UniversalApiInfoDoc>();
+            return communicationProvider.GetApiDocuments().FilterByTags(tags);
+        }
+
+        public void Init(IEnumerable<IProcessor> processors)
+        {
+        }
+
+        public async Task<bool> Start()
+        {
+            try
+            {
+                Console.WriteLine("      Setup Universal Api communicators...");
+                await services.GetRequiredService<UniversalApiHub>()
+                    .InitAsync(this.currentProcessorInstantiatedOperatingResults.Where(r => r.Succeed).Select(r => r.ProcessorInstance));
+                Console.WriteLine("         Setup finished.");
+            }
+            catch (Exception exxx)
+            {
+                mainLogger.LogInformation("     Setup UniversalApiHub Failed: " + exxx);
+                Console.BackgroundColor = ConsoleColor.Red;
+                Console.ForegroundColor = ConsoleColor.Black;
+                Console.WriteLine("     Setup UniversalApiHub Failed: " + exxx);
+                Console.ResetColor();
+                throw;
+            }
+
+            return true;
+        }
+
+        public Task<bool> Stop()
+        {
+            mainLogger.LogError("Stopping DefaultDispatcher processor...");
+            Console.BackgroundColor = ConsoleColor.Red;
+            Console.ForegroundColor = ConsoleColor.Black;
+            Console.WriteLine("             FATAL, Stopping DefaultDispatcher will lose major functions...");
+            Console.ResetColor();
+
+            this.services.GetRequiredService<UniversalApiHub>().CommunicationProviders.ToList().ForEach(c => c.Dispose());
+            return Task.FromResult(true);
+        }
+    }
+}

+ 46 - 0
Edge.Core/Processor/Dispatcher/EventArgs/OnProcessorsLifeCycleChangedEventArg.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Edge.Core.Processor.Dispatcher
+{
+    public class OnProcessorsLifeCycleChangedEventArg
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="operationResults"></param>
+        /// <param name="lifeCycleName"></param>
+        /// <param name="reason">any descriptive info for help understand why this operation happened.</param>
+        public OnProcessorsLifeCycleChangedEventArg(
+            IEnumerable<ProcessorLifeCycleOperationResult> operationResults, string lifeCycleName, string reason)
+        {
+            this.OperationResults = operationResults;// operationResults.Select(r => ProcessorLifeCycleOperationResultDto.From(r));
+            this.LifeCycleName = lifeCycleName;
+            this.Reason = reason;
+            this.TimeStamp = DateTime.Now;
+        }
+
+        public DateTime TimeStamp { get; set; }
+
+        public string LifeCycleName { get; private set; }
+
+        public string Reason { get; private set; }
+
+        /// <summary>
+        /// </summary>
+        public IEnumerable<ProcessorLifeCycleOperationResult> OperationResults { get; private set; }
+    }
+
+    public class OnProcessorsInstantiatedEventArg : System.EventArgs
+    {
+        public OnProcessorsInstantiatedEventArg(
+            IEnumerable<ProcessorInstanceOperatingResult> operationResults)
+        {
+            this.OperationResults = operationResults;
+        }
+
+        public IEnumerable<ProcessorInstanceOperatingResult> OperationResults { get; private set; }
+    }
+}

+ 248 - 0
Edge.Core/Processor/Dispatcher/ProcessorLoader/DbJSonLoader.cs

@@ -0,0 +1,248 @@
+using AutoMapper;
+using Edge.Core.Configuration;
+using Edge.Core.Database;
+using Edge.Core.Database.Configuration.Models;
+using Edge.Core.Parser.BinaryParser;
+using Edge.Core.Processor.Communicator;
+using Edge.Core.Processor.Dispatcher.Attributes;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace Edge.Core.Processor.Dispatcher
+{
+    public class DbJSonLoader : IProcessorLoader, IProcessorMetaConfigAccessor
+    {
+        protected IServiceProvider services;
+        protected static ILogger mainLogger = NullLogger.Instance;
+        private Dictionary<IProcessor, ProcessorMetaConfig> processorInstanceAndMetaConfigDic
+            = new Dictionary<IProcessor, ProcessorMetaConfig>();
+        public DbJSonLoader(IServiceProvider services)
+        {
+            this.services = services;
+            var loggerFactory = services.GetRequiredService<ILoggerFactory>();
+            mainLogger = loggerFactory.CreateLogger("Main");
+        }
+
+        protected virtual IEnumerable<ProcessorMetaConfig> LoadProcessorMetaConfigs()
+        {
+            string json = @"[
+    {
+        ""Id"": 16,
+        ""Name"": ""HengshanPaymentTerminal.HengshanPayTerminal.Hengs_938d2e2bd48b45ba_8"",
+        ""Description"": """",
+        ""Type"": 0,
+        ""Parts"": [
+            {
+                ""Id"": 38,
+                ""Type"": 1,
+                ""FullTypeString"": ""HengshanPaymentTerminal.HengshanPayTermHandler, HengshanPaymentTerminal, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"",
+                ""ParametersJsonArrayStr"": ""[{\""pumpIds\"":\""1,2,3,4\"",\""pumpSubAddresses\"":[{\""PumpId\"":1,\""SubAddress\"":1},{\""PumpId\"":2,\""SubAddress\"":2},{\""PumpId\"":3,\""SubAddress\"":3},{\""PumpId\"":4,\""SubAddress\"":4}],\""pumpNozzleLogicIds\"":[{\""PumpId\"":1,\""LogicIds\"":\""1\""},{\""PumpId\"":2,\""LogicIds\"":\""1\""},{\""PumpId\"":3,\""LogicIds\"":\""1\""},{\""PumpId\"":4,\""LogicIds\"":\""1\""}],\""pumpSiteNozzleNos\"":[{\""PumpId\"":1,\""SiteNozzleNos\"":\""1\""},{\""PumpId\"":2,\""SiteNozzleNos\"":\""2\""},{\""PumpId\"":3,\""SiteNozzleNos\"":\""3\""},{\""PumpId\"":4,\""SiteNozzleNos\"":\""4\""}],\""nozzleLogicIds\"":[{\""NozzleNo\"":1,\""LogicId\"":1},{\""NozzleNo\"":2,\""LogicId\"":1},{\""NozzleNo\"":3,\""LogicId\"":1},{\""NozzleNo\"":4,\""LogicId\"":1}]}]""
+            },
+            {
+                ""Id"": 40,
+                ""Type"": 0,
+                ""FullTypeString"": ""Edge.Core.Processor.GenericDeviceProcessor`2, Edge.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"",
+                ""ParametersJsonArrayStr"": ""[]""
+            },
+            {
+                ""Id"": 41,
+                ""Type"": 5,
+                ""FullTypeString"": ""Edge.Core.Processor.Communicator.TcpServerCommunicator`1, Edge.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"",
+              ""ParametersJsonArrayStr"": ""[8088, 30, \""enabled\"", \""enabled\"", \""2\""]""
+            }
+        ],
+        ""Activated"": true
+    }
+]";
+            IEnumerable<ProcessorMetaConfig> configs = JsonSerializer.Deserialize<IEnumerable<ProcessorMetaConfig>>(json);
+            return configs;
+            //using (var scope = this.services.CreateScope())
+            //{
+            //var dbContext = scope.ServiceProvider.GetRequiredService<SqliteDbContext>();
+            //var mapper = services.GetRequiredService<IMapper>();
+            //var processorMetaConfigs =
+            //mapper.Map<IEnumerable<ProcessorMetaConfig>>(
+            //    dbContext.ProcessorMetaConfigs.Include(i => i.Parts).OrderByDescending(mc => mc.TimeStamp));
+
+            //}
+            // now only for App
+            //var systemInternalComponentEndPointTypes = new List<Type>();
+            //foreach (var loadedAss in ObjectInstanceCreator.CurrentDomainAssemblies)
+            //{
+            //    try
+            //    {
+            //        systemInternalComponentEndPointTypes.AddRange(loadedAss.GetTypes().Where(t =>
+            //            // if already loaded via db metaconfig, then don't load again even IsSystemInternalComponent
+            //            !processorMetaConfigs.SelectMany(mc => mc.Parts).Any(p => p.FullTypeString != t.AssemblyQualifiedName) &&
+            //            !t.IsInterface && !t.IsAbstract &&
+            //            (
+            //                //t.GetInterfaces().Any(ti =>ti.Name == typeof(IDeviceHandler<,>).Name) 
+            //                //||
+            //                typeof(IAppProcessor).IsAssignableFrom(t)
+            //            ) &&
+            //            t.GetCustomAttributes<MetaPartsDescriptor>().Any(att => att.IsSystemInternalComponent)
+            //            )
+            //            );
+            //    }
+            //    catch
+            //    { }
+            //}
+
+            //var processorMetaConfigFromAir = systemInternalComponentEndPointTypes.Select(t => new ProcessorMetaConfig()
+            //{
+            //    Id = new Random().Next(1000, int.MaxValue),
+            //    Activated = true,
+            //    Description = "SystemInternalComponent",
+            //    Name = "SystemInternalComponent_" + t.Name,
+            //    Type = ProcessorTypeEnum.AppProcessor,
+            //    Parts = new List<ProcessorMetaPartsConfig>()
+            //       {
+            //           new ProcessorMetaPartsConfig()
+            //           {
+            //                Id = new Random().Next(1000, int.MaxValue),
+            //                FullTypeString  = t.AssemblyQualifiedName,
+            //                Type = ProcessorMetaPartsTypeEnum.App,
+            //                ParametersJsonArrayStr = "["+
+            //                    t.GetCustomAttributes<MetaPartsDescriptor>().First(att=>att.IsSystemInternalComponent).DefaultCtorParamsJsonStrings.Aggregate((acc,n)=>acc+","+n)+"]",
+            //           }
+            //       }
+            //});
+            //return processorMetaConfigs.Concat(processorMetaConfigFromAir);
+        }
+
+        public IEnumerable<ProcessorInstanceOperatingResult> CreateAll()
+        {
+            this.processorInstanceAndMetaConfigDic.Clear();
+            mainLogger.LogInformation("Use DbJSonLoader for Processor Meta Config.");
+            mainLogger.LogInformation("==============Instantiate Processors (by DbJSonLoader)==============");
+            Console.WriteLine();
+            Console.WriteLine("==============Instantiate Processors (by DbJSonLoader)==============");
+
+            var processorMetaConfigs = this.LoadProcessorMetaConfigs().Where(c => c.Activated);
+            if (processorMetaConfigs == null || !processorMetaConfigs.Any())
+            {
+                //mainLogger.LogInformation("Found IDeviceHandler or IAppProcessor type: " + t.FullName + " but there's no meta config defined for it, will skip it");
+                mainLogger.LogInformation("Found empty MetaConfig in db");
+                mainLogger.LogInformation("==============Instantiate Processors End==============");
+                Console.WriteLine("==============Instantiate Processors End==============");
+                return Enumerable.Empty<ProcessorInstanceOperatingResult>();
+            }
+
+            var createResults = new List<ProcessorInstanceOperatingResult>();
+            processorMetaConfigs.ToList().ForEach(mc =>
+            {
+                mainLogger.LogInformation("constructing [id:" + mc.Id + "]: " + mc.Name + ", type: " + mc.Type);// + ", from: " + t.Assembly.FullName + ", assemblyPath: " + t.Assembly.Location);
+                Console.WriteLine("[id:" + mc.Id + "]: " + mc.Name);// + " from: " + t.Assembly.GetName().Name);
+                try
+                {
+                    var p = ObjectInstanceCreator.CreateProcessor<IProcessor>(mc, new object[] { this.services });
+                    createResults.Add(new ProcessorInstanceOperatingResult()
+                    {
+                        Succeed = true,
+                        ProcessorInstance = p,
+                        HostVersion = Assembly.GetAssembly(p.GetType()).GetName().Version.ToString(),
+                        CoreVersion = Assembly.GetAssembly(typeof(IProcessor)).GetName().Version.ToString(),
+                        MetaConfig = mc,
+                    });
+                    this.processorInstanceAndMetaConfigDic.Add(p, mc);
+                }
+                catch (Exception exxxxx)
+                {
+                    createResults.Add(new ProcessorInstanceOperatingResult()
+                    {
+                        Succeed = false,
+                        MetaConfig = mc,
+                        CoreVersion = Assembly.GetAssembly(typeof(IProcessor)).GetName().Version.ToString(),
+                        FailedReason = exxxxx.ToString()
+                    });
+                    mainLogger.LogError(" - Failed for instantiate: " + "[id:" + mc.Id + "]: " + mc.Name + ", type: " + mc.Type
+                        //+ ", from: " + t.Assembly.FullName + ", assemblyPath: " + t.Assembly.Location 
+                        + Environment.NewLine + "   " + exxxxx.ToString());
+                    Console.BackgroundColor = ConsoleColor.Red;
+                    Console.ForegroundColor = ConsoleColor.Black;
+                    Console.WriteLine(" - Failed for instantiate: " + "[id:" + mc.Id + "]: " + mc.Name + Environment.NewLine + "   " + exxxxx.ToString().Substring(0, 90) + "...");
+                    Console.ResetColor();
+                }
+            });
+            mainLogger.LogInformation("==============Instantiate Processors End==============");
+            Console.WriteLine("==============Instantiate Processors End==============");
+            return createResults;
+        }
+
+        public IProcessor Create(string configName)
+        {
+            if (string.IsNullOrEmpty(configName)) throw new ArgumentException(nameof(configName));
+            //ignore the IsActivated
+            var processorMetaConfig = this.LoadProcessorMetaConfigs().First(mc => mc.Name == configName);
+            var p = ObjectInstanceCreator.CreateProcessor<IProcessor>(processorMetaConfig, new object[] { this.services });
+            return p;
+        }
+
+        public async Task<ProcessorMetaPartsConfig> GetMetaPartsMetaConfigAsync(
+            IProcessor processor, ProcessorMetaPartsTypeEnum metaPartsType)
+        {
+            if (!this.processorInstanceAndMetaConfigDic.TryGetValue(processor, out ProcessorMetaConfig pMetaConfig))
+                return null;
+            using (var scope = this.services.CreateScope())
+            {
+            
+                return null;
+            }
+        }
+
+        public async Task<ProcessorMetaPartsConfig> UpdateMetaPartsMetaConfigAsync(
+            IProcessor processor, ProcessorMetaPartsTypeEnum metaPartsType, object[] parameters)
+        {
+            if (!this.processorInstanceAndMetaConfigDic.TryGetValue(processor, out ProcessorMetaConfig pMetaConfig))
+                return null;
+            using (var scope = this.services.CreateScope())
+            {
+                return null;
+            }
+        }
+
+        public async Task<bool> RemoveMetaPartsMetaConfigAsync(IProcessor processor, int processorMetaPartsConfigId)
+        {
+            if (!this.processorInstanceAndMetaConfigDic.TryGetValue(processor, out ProcessorMetaConfig pMetaConfig))
+                return false;
+            using (var scope = this.services.CreateScope())
+            {
+                return false;
+            }
+        }
+
+        public async Task<IEnumerable<ProcessorMetaConfig>> GetMetaConfigAsync()
+        {
+            return await this.GetMetaConfigAsync(null);
+        }
+
+        /// <summary>
+        /// Get the meta configs by its linked sourceEndpointFullTypeStr with *sql likes* input parameter.
+        /// </summary>
+        /// <param name="sourceEndpointFullTypeStr"></param>
+        /// <returns></returns>
+        public async Task<IEnumerable<ProcessorMetaConfig>> GetMetaConfigAsync(string sourceEndpointFullTypeStr)
+        {
+            return null;
+        }
+
+        public async Task<ProcessorMetaConfig> UpsertMetaConfigAsync(ProcessorMetaConfig metaConfig)
+        {
+            return null;
+        }
+
+        public async Task<bool> RemoveMetaConfigAsync(int metaConfigId)
+        {
+            return false;
+        }
+    }
+}

+ 72 - 0
Edge.Core/Processor/Dispatcher/ProcessorLoader/IProcessorLoader.cs

@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Edge.Core.Processor.Dispatcher
+{
+    public interface IProcessorLoader
+    {
+        /// <summary>
+        /// Create (Instantiate) all Processor instances based on underlying configs.
+        /// </summary>
+        /// <returns></returns>
+        IEnumerable<ProcessorInstanceOperatingResult> CreateAll();
+
+        /// <summary>
+        /// Create (Instantiate) a single Processor instance based on config name.
+        /// </summary>
+        /// <param name="configName"></param>
+        /// <returns></returns>
+        IProcessor Create(string configName);
+    }
+
+    public interface IProcessorMetaConfigAccessor
+    {
+        /// <summary>
+        /// Get all meta configs from uderlying persist ProcessorMetaConfigs.
+        /// </summary>
+        /// <returns>each source Endpoint Type could have multiple configs</returns>
+        Task<IEnumerable<ProcessorMetaConfig>> GetMetaConfigAsync();
+        /// <summary>
+        /// Get meta configs from uderlying persist ProcessorMetaConfigs with searching condition of SourceEndpointFullTypeStr.
+        /// </summary>
+        /// <param name="sourceEndpointFullTypeStr">sample like-> Applications.FDC.FdcServerHostApp, FdcServerHost, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</param>
+        /// <returns>each source Endpoint Type could have multiple configs</returns>
+        Task<IEnumerable<ProcessorMetaConfig>> GetMetaConfigAsync(string sourceEndpointFullTypeStr);
+
+        ///// <summary>
+        ///// Get meta configs from uderlying persist ProcessorMetaConfigs with searching condition of SourceEndpointFullTypeStr.
+        ///// </summary>
+        ///// <param name="metaConfigId"></param>
+        ///// <returns></returns>
+        //Task<ProcessorMetaConfig> GetMetaConfigAsync(int metaConfigId);
+
+        Task<ProcessorMetaConfig> UpsertMetaConfigAsync(ProcessorMetaConfig metaConfig);
+        Task<bool> RemoveMetaConfigAsync(int metaConfigId);
+
+        /// <summary>
+        /// Used for internally(AppProcessor or DeviceHanlder?) to get the meta parts config for a processor.
+        /// </summary>
+        /// <param name="processor">instance of the processsor</param>
+        /// <param name="metaPartsType"></param>
+        /// <returns></returns>
+        Task<ProcessorMetaPartsConfig> GetMetaPartsMetaConfigAsync(IProcessor processor,
+            ProcessorMetaPartsTypeEnum metaPartsType);
+        /// <summary>
+        /// Used for internally(AppProcessor or DeviceHanlder?) to upsert the meta parts config for a processor.
+        /// </summary>
+        /// <param name="processor"></param>
+        /// <param name="metaPartsType"></param>
+        /// <param name="parameters"></param>
+        /// <returns></returns>
+        Task<ProcessorMetaPartsConfig> UpdateMetaPartsMetaConfigAsync(IProcessor processor,
+            ProcessorMetaPartsTypeEnum metaPartsType, object[] parameters);
+        /// <summary>
+        /// Used for internally(AppProcessor or DeviceHanlder?) to remove the meta parts config for a processor.
+        /// </summary>
+        /// <param name="processorMetaPartsConfigId"></param>
+        /// <returns></returns>
+        Task<bool> RemoveMetaPartsMetaConfigAsync(IProcessor processor, int processorMetaPartsConfigId);
+    }
+}

+ 304 - 0
Edge.Core/Processor/Dispatcher/ProcessorLoader/LegacySettingsXmlFileLoader.cs

@@ -0,0 +1,304 @@
+using Edge.Core.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace Edge.Core.Processor.Dispatcher
+{
+    public class LegacySettingsXmlFileLoader : IProcessorLoader
+    {
+        protected IServiceProvider services;
+        protected static ILogger mainLogger = NullLogger.Instance;
+
+        public LegacySettingsXmlFileLoader(IServiceProvider services)
+        {
+            this.services = services;
+            var loggerFactory = services.GetRequiredService<ILoggerFactory>();
+            mainLogger = loggerFactory.CreateLogger("Main");
+        }
+
+        public IEnumerable<ProcessorInstanceOperatingResult> CreateAll()
+        {
+            mainLogger.LogInformation("Use LegacySettingsXmlFileLoader for Processor Meta Config.");
+            Console.WriteLine("Use LegacySettingsXmlFileLoader for Processor Meta Config.");
+
+            var configurator = this.services.GetRequiredService<Configurator>();
+            var processorConfigs = configurator.DeviceProcessorConfiguration.Processor.OrderBy(pc => pc.Name).ToList();
+            mainLogger.LogInformation("==============Instantiate Processors (total: " + processorConfigs.Count() + ")==============");
+            Console.WriteLine();
+            Console.WriteLine("==============Instantiate Processors (total: " + processorConfigs.Count() + ")==============");
+
+            //List<IProcessor> processorInstances = new List<IProcessor>();
+            var createResults = new List<ProcessorInstanceOperatingResult>();
+            for (int i = 0; i < processorConfigs.Count; i++)
+            {
+                var pc = processorConfigs[i];
+                try
+                {
+                    mainLogger.LogInformation("[" + i + "]: " + pc.Name + ", " + pc.DeviceProcessorType);
+                    Console.WriteLine("[" + i + "]: " + pc.Name + ", " + pc.DeviceProcessorType);
+                    var parameters = pc.Parameter;//.Cast<DeviceProcessorParameter>();
+                    foreach (var para in parameters)
+                    {
+                        mainLogger.LogInformation("            " + para.Name + " : " + para.Value);
+                        //Console.WriteLine("            " + para.Name + " : " + para.Value);
+                    }
+
+                    var processorInstance =
+                        ConstructComplexType_Xml_String(pc.DeviceProcessorType, pc.ConstructorArg, parameters, services) as IProcessor;
+                    processorInstance.MetaConfigName = pc.Name;
+                    createResults.Add(new ProcessorInstanceOperatingResult()
+                    {
+                        MetaConfig = new ProcessorMetaConfig()
+                        {
+                            Name = pc.Name,
+                            Activated = true,
+                            SourceEndpointFullTypeStr = pc.DeviceProcessorType,
+                            Type = processorInstance is IAppProcessor ? ProcessorTypeEnum.AppProcessor : ProcessorTypeEnum.DeviceProcessor,
+                            Description = "Current using Legacy Settings XmlFile mode, so this is a fake ProcessorMetaConfig"
+                        },
+                        //Description = "Legacy Settings XmlFile mode for instantiate a processor, and succeed",
+                        Succeed = true,
+                        ProcessorInstance = processorInstance,
+                        //MetaConfig = mc,
+                    });
+                }
+                catch (Exception eee)
+                {
+                    createResults.Add(new ProcessorInstanceOperatingResult()
+                    {
+                        MetaConfig = new ProcessorMetaConfig()
+                        {
+                            Name = pc.Name,
+                            Activated = true,
+                            SourceEndpointFullTypeStr = pc.DeviceProcessorType,
+                            Description = "Current using Legacy Settings XmlFile mode, so this is a fake ProcessorMetaConfig"
+                        },
+                        //Description = "Legacy Settings XmlFile mode for instantiate a processor, but failed",
+                        Succeed = false,
+                        //MetaConfig = mc,
+                        FailedReason = eee.ToString()
+                    });
+                    mainLogger.LogError(" - Failed for instantiate: " + pc.Name + Environment.NewLine + "   " + eee.ToString());
+                    Console.BackgroundColor = ConsoleColor.Red;
+                    Console.ForegroundColor = ConsoleColor.Black;
+                    Console.WriteLine(" - Failed for instantiate: " + pc.Name + Environment.NewLine + "   " + eee.ToString().Substring(0, 90) + "...");
+                    Console.ResetColor();
+                }
+            }
+
+            mainLogger.LogInformation("==============Instantiate Processors End==============");
+            Console.WriteLine("==============Instantiate Processors End==============");
+
+            return createResults;
+        }
+
+        public IProcessor Create(string configName)
+        {
+            if (string.IsNullOrEmpty(configName)) throw new ArgumentException(nameof(configName));
+            var configurator = this.services.GetRequiredService<Configurator>();
+            var processorConfig = configurator.DeviceProcessorConfiguration.Processor.First(settingsXmlConfig => settingsXmlConfig.Name == configName);
+            var p =
+                ConstructComplexType_Xml_String(
+                    processorConfig.DeviceProcessorType,
+                    processorConfig.ConstructorArg,
+                    processorConfig.Parameter, services) as IProcessor;
+            p.MetaConfigName = processorConfig.Name;
+            return p;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="typeFullyQualifiedNameString">nameSpace.ClassA, AssemblyFileName</param>
+        /// <param name="constrStrFromConfig"></param>
+        /// <param name="parameters"></param>
+        /// <param name="services"></param>
+        /// <returns></returns>
+        protected virtual dynamic ConstructComplexType_Xml_String(string typeFullyQualifiedNameString, string constrStrFromConfig, IEnumerable<ProcessorParameter> parameters, IServiceProvider services)
+        {
+            Type processorType = Type.GetType(typeFullyQualifiedNameString);
+            if (processorType == null)
+            {
+                var fallbackToVersion2NameString = Fallback_Version2_ResolveType_Compatbility(typeFullyQualifiedNameString);
+                processorType = Type.GetType(fallbackToVersion2NameString);
+                if (processorType == null)
+                    throw new ArgumentException("Could not resolve type: " + typeFullyQualifiedNameString);
+                else
+                    typeFullyQualifiedNameString = fallbackToVersion2NameString;
+            }
+
+            if (string.IsNullOrEmpty(constrStrFromConfig))
+            {
+                try
+                {
+                    //now only support injecting one parameter.
+                    var injectingCtor = processorType.GetConstructors().FirstOrDefault(c => c.GetParameters().Length == 1);
+                    if (injectingCtor != null
+                        && injectingCtor.GetParameters().First().ParameterType == typeof(IServiceProvider))
+                    {
+                        mainLogger.LogTrace("Constructing instance(with 1 param ctor and empty param from config) with type: " + processorType.Name);
+                        mainLogger.LogTrace("   - ctor parameter with name: " + injectingCtor.GetParameters().First().Name + " is type IServiceProvider, will injecting");
+                        var injectedInstance = Activator.CreateInstance(processorType, new object[] { services });
+                        mainLogger.LogTrace("  Done constructing instance(with 1 param ctor and empty param from config) with type: " + processorType.Name);
+                        return injectedInstance;
+                    }
+
+                    mainLogger.LogTrace("Constructing instance(with empty param ctor and empty param from config) with type: " + processorType.Name);
+                    var parameterlessInstance = Activator.CreateInstance(processorType);
+                    mainLogger.LogTrace("  Done constructing instance(with empty param ctor and empty param from config) with type: " + processorType.Name);
+                    return parameterlessInstance;
+                }
+                catch (Exception exxx)
+                {
+                    //mainLogger.LogError();
+                    throw new InvalidOperationException("CreateInstance(with empty ctor) for: "
+                        + typeFullyQualifiedNameString + " failed, " + Environment.NewLine + " exception detail: " + exxx);
+                }
+            }
+            else
+            {
+                List<object> cArgsFromConfig = new List<object>();
+                var constructorArgStrings = constrStrFromConfig.Replace("\r", "").Replace("\n", "").Split(',').Select(s => s.Trim()).ToArray();
+                for (int i = 0; i < constructorArgStrings.Length; i++)
+                {
+                    var argStr = constructorArgStrings[i];
+                    try
+                    {
+                        if (!argStr.StartsWith("ref:"))
+                        {
+                            cArgsFromConfig.Add(readPrimitiveParameterValue(argStr));
+                        }
+                        else if (argStr.StartsWith("ref:"))
+                        {
+                            var refTo = argStr.Substring(4);
+                            // quick ref
+                            if (refTo.Contains(':'))
+                            {
+                                var quickRefValuePart = refTo.Split(':').Last();
+                                cArgsFromConfig.Add(readPrimitiveParameterValue(quickRefValuePart));
+                            }
+                            else
+                            {
+                                var refParameter = parameters.First(p => p.Name == refTo);
+                                if (!refParameter.Complex)
+                                {
+                                    cArgsFromConfig.Add(readPrimitiveParameterValue(refParameter.Value));
+                                }
+                                else
+                                {
+                                    var complexArg = ConstructComplexType_Xml_String(refParameter.Value, refParameter.ConstructorArg, parameters, services);
+                                    cArgsFromConfig.Add(complexArg);
+                                }
+                            }
+                        }
+                    }
+                    catch (Exception exxx)
+                    {
+                        throw new InvalidOperationException("failed for parse constructor arg[" + i + "]: " + argStr
+                            + " " + Environment.NewLine + " for type: " + processorType.Name
+                            + " " + Environment.NewLine + " detail: " + exxx);
+                    }
+                    //else if (argStr.StartsWith("refIdArray("))
+                    //{
+                    //    var idsString = argStr.Skip("refIdArray(".Length).TakeWhile(p => p != ')')
+                    //        .Select(c => c.ToString()).Aggregate((acc, n) => acc + n);
+                    //    var output = processors.Where(p => idsString.Trim().Split('|').ToList().Contains(p.Id.ToString()));
+                    //    cArgs.Add(output);
+                    //}
+                }
+
+                //var cc = deviceProcessorType.GetConstructors();
+                try
+                {
+                    mainLogger.LogTrace("Constructing instance(with multiple param ctor and "
+                        + cArgsFromConfig.Count + " param from config) with type: " + processorType.Name);
+                    //now only support injecting one parameter.
+                    var injectingCtor = processorType.GetConstructors().FirstOrDefault(c => c.GetParameters().Length == cArgsFromConfig.Count + 1);
+                    //for(int c=0;c<injectingCtors.Count())
+                    //{
+                    if (injectingCtor != null)
+                    {
+                        var ctParams = injectingCtor.GetParameters();
+                        for (int i = 0; i < ctParams.Length; i++)
+                        {
+                            var param = ctParams[i];
+                            if (param.ParameterType == typeof(IServiceProvider))
+                            {
+                                mainLogger.LogTrace("   - ctor parameter with name: " + ctParams[i].Name + " is type IServiceProvider, will injecting");
+                                cArgsFromConfig.Insert(i, services);
+                            }
+                        }
+                    }
+                    //}
+
+                    var s = Activator.CreateInstance(processorType, cArgsFromConfig.ToArray());
+                    mainLogger.LogTrace("  Done constructing instance with type: " + processorType.Name);
+                    return s;
+                }
+                catch (Exception exxx)
+                {
+                    throw new InvalidOperationException("CreateInstance(with ctor args: "
+                        + cArgsFromConfig.Select(c => c.ToString()).Aggregate((acc, n) => acc + ", " + n) + ") for: " + processorType.Name + " failed, \r\n exception detail: " + exxx);
+                }
+            }
+        }
+
+        protected virtual object readPrimitiveParameterValue(string valueStr)
+        {
+            if (valueStr.StartsWith("ref:")) throw new ArgumentException("ONLY can read primitive parameter value");
+            if (valueStr == "") return "";
+            if (valueStr.StartsWith("'")) return valueStr.Substring(1, valueStr.Length - 2);
+            int intResult = -1;
+            var intParseResult = int.TryParse(valueStr, out intResult);
+            if (intParseResult) return intResult;
+            else return valueStr;
+        }
+
+        /// <summary>
+        /// version 3 combind DeviceProcessor, Communicator, Parser, Common into one project and namespace also adjusted.
+        /// it'll break the old setting.xml, so here try to recover it by overwirte the old namespace and assembly name.
+        /// </summary>
+        /// <param name="version2TypeFullyQualifiedNameString"></param>
+        /// <returns></returns>
+        internal static string Fallback_Version2_ResolveType_Compatbility(string version2TypeFullyQualifiedNameString)
+        {
+            if (Regex.IsMatch(version2TypeFullyQualifiedNameString,
+                "^\\s{0,}(DeviceProcessor|Communicator)(\\..+)(\\1)\\s{0,}$"))
+            {
+                /* the old one likes(the content between the ""):
+                 *      deviceProcessorType="DeviceProcessor.GenericDeviceProcessor`2[[System.Byte[]], [ProGauge_StartItaliana_Probe.MessageEntity.MessageBase, ProGauge_StartItaliana_Probe]], DeviceProcessor"
+                 *      deviceProcessorType="DeviceProcessor.HalfDuplexActivePollingDeviceProcessor`2[[System.Byte[]], [OPW_VaporRecoveryOnlineWatch_DataCollector.DataCollectorMessageBase,OPW_VaporRecoveryOnlineWatch_DataCollector]], DeviceProcessor"
+                 *      name="deviceHandlerType" value="ProGauge_StartItaliana_Probe.Handler,ProGauge_StartItaliana_Probe"
+                 *      name="deviceHandlerType" value="LanTian_Pump_664_Or_886.PumpGroupHandler,LanTian_Pump_664_Or_886"
+                 *      name="communicatorType"  value="Communicator.ComPortCommunicator`1[[ProGauge_StartItaliana_Probe.MessageEntity.MessageBase,ProGauge_StartItaliana_Probe]],Communicator"
+                 *      name="communicatorType" value="Communicator.TcpClientCommunicator`1[[VeederRoot_ATG_Console.MessageEntity.MessageBaseGeneric,VeederRoot_ATG_Console]],Communicator"
+                 */
+                version2TypeFullyQualifiedNameString = version2TypeFullyQualifiedNameString.Replace(" ", "");
+                return version2TypeFullyQualifiedNameString
+                    .Replace("DeviceProcessor.", "Edge.Core.Processor.")
+                    .Replace(",DeviceProcessor", ",Edge.Core")
+                    .Replace("Communicator.", "Edge.Core.Processor.Communicator.")
+                    .Replace(",Communicator", ",Edge.Core");
+            }
+            else if (Regex.IsMatch(version2TypeFullyQualifiedNameString,
+                "(DeviceProcessor|Communicator|Parser|Common),\\sCulture=\\w+?,\\sPublicKeyToken=\\w+"))
+            {
+                /* the old one likes: DeviceProcessor, Culture=neutral, PublicKeyToken=null */
+                return version2TypeFullyQualifiedNameString
+                        .Replace("DeviceProcessor", "Edge.Core")
+                        .Replace("Communicator", "Edge.Core")
+                        .Replace("Parser", "Edge.Core")
+                        .Replace("Common", "Edge.Core");
+            }
+            else
+                return version2TypeFullyQualifiedNameString;
+        }
+    }
+}

+ 54 - 0
Edge.Core/Processor/Dispatcher/ProcessorLoader/ProcessorLoaderFactory.cs

@@ -0,0 +1,54 @@
+using Edge.Core.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Edge.Core.Processor.Dispatcher.ProcessorLoader
+{
+    public static class ProcessorLoaderFactory
+    {
+        public static IProcessorLoader Create(IServiceProvider services)
+        {
+            IProcessorLoader loader = null;
+            //List<Type> processorLoaderTypes = new List<Type>();
+            //foreach (var ass in ObjectInstanceCreator.CurrentDomainAssemblies)
+            //{
+            //    try
+            //    {
+            //        //var ass = Assembly.LoadFrom(ai.FullName);
+            //        var t = ass.GetTypes().Where(t => typeof(IProcessorLoader).IsAssignableFrom(t)
+            //            && !t.IsInterface);
+            //        if (t != null && t.Any()) processorLoaderTypes.AddRange(t);
+            //    }
+            //    catch
+            //    { }
+            //}
+
+            if ((Configurator.Default.DeviceProcessorConfiguration?.Processor?.Count ?? 0) == 0)
+            {
+                var loaderTypeStr = Configurator.Default.MetaConfiguration
+                    ?.Parameter?.FirstOrDefault(p => p.Name.Equals("processorLoaderType", StringComparison.OrdinalIgnoreCase))?.Value;
+                if (string.IsNullOrEmpty(loaderTypeStr))
+                    loader = new DbJSonLoader(services);
+                else
+                    loader = ObjectInstanceCreator.Create(loaderTypeStr, null, new Type[] { }, new object[] { services }) as IProcessorLoader;
+            }
+            else
+            {
+                loader = new LegacySettingsXmlFileLoader(services);
+            }
+
+            return loader;
+        }
+    }
+
+    public static class ProcessorMetaConfigAccessorFactory
+    {
+        public static IProcessorMetaConfigAccessor Create(IServiceProvider services)
+        {
+            var loader = services.GetService(typeof(IProcessorLoader));
+            return loader as IProcessorMetaConfigAccessor;
+        }
+    }
+}

+ 15 - 15
HengshanPaymentTerminal/MessageTemplateLookup.cs

@@ -24,48 +24,48 @@ namespace HengshanPaymentTerminal
         static MessageTemplateLookup()
         {
             messageCodeToTypeStrDict.Add("0x10",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.CheckCmdRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.CheckCmdRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x13",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.RegisterRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.RegisterRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x15",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.ValidateCardRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.ValidateCardRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x17",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.AuthRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.AuthRequest,HengshanPaymentTerminal");
             messageCodeToTypeStrDict.Add("0x19",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.CancelAuthRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.CancelAuthRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x1C",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.FuelingDataRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.FuelingDataRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x20",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.ChangeAuthModeAck,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.ChangeAuthModeAck,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x21",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.QueryGrayRecordRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.QueryGrayRecordRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x2D",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.TransactionDataRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.TransactionDataRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x30",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.PaymentRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.PaymentRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x45",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.LockOrUnlockPumpAck,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.LockOrUnlockPumpAck,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x24",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.VolumeTotal,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.VolumeTotal,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x25",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.DataDownloadRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.DataDownloadRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x27",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.DataContentRequest,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.DataContentRequest,HengshanPaymentTerminal");
 
             messageCodeToTypeStrDict.Add("0x49",
-                " HengshanPaymentTerminal.MessageEntity.Incoming.Totalizer,Dfs.WayneChina.HengshanPayTerminal");
+                "HengshanPaymentTerminal.MessageEntity.Incoming.Totalizer,HengshanPaymentTerminal");
         }
 
         public MessageTemplateBase GetMessageTemplateByRawBytes(byte[] bytes)

+ 117 - 112
HengshanPaymentTerminal/StateMachineMessageCutter.cs

@@ -50,118 +50,123 @@ namespace HengshanPaymentTerminal
 
             window.OnWindowFull += (data) =>
             {
-                switch (nextState)
-                {
-                    case State.Uninitialized:
-                        if (data.First() == STX)
-                        {
-                            window.NewSize = 6;
-                            nextState = State.LengthReady;
-                        }
-                        else
-                        {
-                            OnInvalidMessageRead?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()
-                            {
-                                Message = "invalid byte[0]: 0x" + data.First().ToString("x2") + ", will skip"
-                            });
-                            window.Clear();
-                        }
-                        break;
-
-                    case State.LengthReady:
-
-                        var countSTX = window.Count(b => b == STX);
-                        if (countSTX > 1)
-                        {
-                            //Console.WriteLine($"0xFA count: {countSTX}");
-                            innerLogger.Info($"0xFA count: {countSTX}");
-                            int index = window.ToList().LastIndexOf(STX);
-
-
-                            var tempArray = window.Skip(index).ToArray();
-                            window.Clear();
-                            nextState = State.Uninitialized;
-                            Feed(tempArray);
-
-                            return;
-
-
-                        }
-
-
-
-                        int bodyLen = window[4] * 10 + window[5];
-
-                        if (bodyLen > 256 || bodyLen < 2)
-                        {
-                            var safe8 = this.OnInvalidMessageRead;
-                            safe8?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()
-                            {
-                                Message = "Message body length is not valid, len is: " + bodyLen
-                            });
-                            nextState = State.Uninitialized;
-                            window.Clear();
-                            window.NewSize = 1;
-                            return;
-                        }
-
-                        window.NewSize += bodyLen;
-                        nextState = State.BodyReady;
-
-                        break;
-
-                    case State.BodyReady:
-
-                        window.NewSize = window.Skip(4).Take(2).ToArray().ToInt32() + 6 + 3;
-                        nextState = State.CrcReady;
-                        break;
-
-                    case State.CrcReady:
-
-                        var stxCount = window.Count(b => b == STX);
-                        if (stxCount > 1)
-                        {
-                            //Console.WriteLine($"0xFA count: {stxCount}");
-                            innerLogger.Info($"0xFA count: {stxCount}");
-                            int length = window.Count;
-                            if (window[length - 3] == 0xFF)
-                            {
-                                //Console.WriteLine("ETX exists, consider it a complete message");
-                                innerLogger.Info("ETX exists, consider it a complete message");
-                            }
-                            else
-                            {
-                                int index = window.ToList().LastIndexOf(STX);
-
-                                if (index + 2 <= window.Count - 1)
-                                {
-                                    byte trailingByte1 = window[index + 1];
-                                    byte trailingByte2 = window[index + 2];
-
-                                    if (trailingByte1 == trailingByte2 && trailingByte1 <= 6 && trailingByte1 > 0)
-                                    {
-                                        //Console.WriteLine("Possible mix of incompleted messages");
-                                        innerLogger.Info("Possible mix of incompleted messages");
-                                        var tempArray = window.Skip(index).ToArray();
-                                        window.Clear();
-                                        nextState = State.Uninitialized;
-                                        Feed(tempArray);
-
-                                        return;
-                                    }
-                                }
-                            }
-                        }
-
-                        Message = window.ToArray();
-                        var safe = OnMessageCut;
-                        safe?.Invoke(this, null);
-                        nextState = State.Uninitialized;
-                        window.Clear();
-                        break;
-                    default:
-                        throw new ArgumentOutOfRangeException();
-                }
+                Message = window.ToArray();
+                var safe = OnMessageCut;
+                safe?.Invoke(this, null);
+                nextState = State.Uninitialized;
+                window.Clear();
+                //switch (nextState)
+                //{
+                //    case State.Uninitialized:
+                //        if (data.First() == STX)
+                //        {
+                //            window.NewSize = 6;
+                //            nextState = State.LengthReady;
+                //        }
+                //        else
+                //        {
+                //            OnInvalidMessageRead?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()
+                //            {
+                //                Message = "invalid byte[0]: 0x" + data.First().ToString("x2") + ", will skip"
+                //            });
+                //            window.Clear();
+                //        }
+                //        break;
+
+                //    case State.LengthReady:
+
+                //        var countSTX = window.Count(b => b == STX);
+                //        if (countSTX > 1)
+                //        {
+                //            //Console.WriteLine($"0xFA count: {countSTX}");
+                //            innerLogger.Info($"0xFA count: {countSTX}");
+                //            int index = window.ToList().LastIndexOf(STX);
+
+
+                //            var tempArray = window.Skip(index).ToArray();
+                //            window.Clear();
+                //            nextState = State.Uninitialized;
+                //            Feed(tempArray);
+
+                //            return;
+
+
+                //        }
+
+
+
+                //        int bodyLen = window[4] * 10 + window[5];
+
+                //        if (bodyLen > 256 || bodyLen < 2)
+                //        {
+                //            var safe8 = this.OnInvalidMessageRead;
+                //            safe8?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()
+                //            {
+                //                Message = "Message body length is not valid, len is: " + bodyLen
+                //            });
+                //            nextState = State.Uninitialized;
+                //            window.Clear();
+                //            window.NewSize = 1;
+                //            return;
+                //        }
+
+                //        window.NewSize += bodyLen;
+                //        nextState = State.BodyReady;
+
+                //        break;
+
+                //    case State.BodyReady:
+
+                //        window.NewSize = window.Skip(4).Take(2).ToArray().ToInt32() + 6 + 3;
+                //        nextState = State.CrcReady;
+                //        break;
+
+                //    case State.CrcReady:
+
+                //        var stxCount = window.Count(b => b == STX);
+                //        if (stxCount > 1)
+                //        {
+                //            //Console.WriteLine($"0xFA count: {stxCount}");
+                //            innerLogger.Info($"0xFA count: {stxCount}");
+                //            int length = window.Count;
+                //            if (window[length - 3] == 0xFF)
+                //            {
+                //                //Console.WriteLine("ETX exists, consider it a complete message");
+                //                innerLogger.Info("ETX exists, consider it a complete message");
+                //            }
+                //            else
+                //            {
+                //                int index = window.ToList().LastIndexOf(STX);
+
+                //                if (index + 2 <= window.Count - 1)
+                //                {
+                //                    byte trailingByte1 = window[index + 1];
+                //                    byte trailingByte2 = window[index + 2];
+
+                //                    if (trailingByte1 == trailingByte2 && trailingByte1 <= 6 && trailingByte1 > 0)
+                //                    {
+                //                        //Console.WriteLine("Possible mix of incompleted messages");
+                //                        innerLogger.Info("Possible mix of incompleted messages");
+                //                        var tempArray = window.Skip(index).ToArray();
+                //                        window.Clear();
+                //                        nextState = State.Uninitialized;
+                //                        Feed(tempArray);
+
+                //                        return;
+                //                    }
+                //                }
+                //            }
+                //        }
+
+                //        Message = window.ToArray();
+                //        var safe = OnMessageCut;
+                //        safe?.Invoke(this, null);
+                //        nextState = State.Uninitialized;
+                //        window.Clear();
+                //        break;
+                //    default:
+                //        throw new ArgumentOutOfRangeException();
+                //}
             };
         }
 

+ 5 - 0
src/FccLife.Web/FccLite.Web.csproj

@@ -13,6 +13,11 @@
     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
   </ItemGroup>
 
+  <ItemGroup>
+    <ProjectReference Include="..\..\Edge.Core\Edge.Core.csproj" />
+    <ProjectReference Include="..\..\HengshanPaymentTerminal\HengshanPaymentTerminal.csproj" />
+  </ItemGroup>
+
   <ItemGroup>
     <Content Update="nlog.config">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>

+ 22 - 1
src/FccLife.Web/Program.cs

@@ -8,9 +8,12 @@ using FccLite.Web.Services.FccStaionInfo;
 using FccLite.Web.Services.FccTankInfo;
 using FccLite.Web.utils.database;
 using Microsoft.EntityFrameworkCore;
+using Edge.Core.Processor.Dispatcher;
+using Edge.Core.Processor;
+using Edge.Core.Processor.Dispatcher.ProcessorLoader;
 
 var builder = WebApplication.CreateBuilder(args);
-
+ DefaultDispatcher processorsDispatcher = null;
 //数据库
 builder.Services.AddDbContext<MysqlDbContext>(options =>
     options.UseMySql(builder.Configuration.GetConnectionString("DefaultConnection"), ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("DefaultConnection")))
@@ -39,6 +42,24 @@ builder.Services.AddSwaggerGen(c =>
         Description = "二维码项目 FCC 页面接口",
     });
 });
+{
+    builder.Services.AddSingleton(ProcessorLoaderFactory.Create);
+    builder.Services.AddSingleton(ProcessorMetaConfigAccessorFactory.Create);
+    var serviceProvider = builder.Services.BuildServiceProvider();
+ 
+
+    Console.CancelKeyPress += (sender, arg) =>
+    {
+
+        Environment.Exit(-1);
+    };
+    processorsDispatcher = new DefaultDispatcher(serviceProvider);
+    IEnumerable<ProcessorInstanceOperatingResult> instantiateResults = null;
+    instantiateResults = await processorsDispatcher.CreateProcessorsAsync("Main starting", false);
+    var startResults = await processorsDispatcher.StartProcessorsAsync(
+                 instantiateResults.Where(r => r.Succeed).Select(r => r.ProcessorInstance),
+                 "Main starting");
+}
 var app = builder.Build();
 
 //controller