• 看我如何快速学习.Net(高可用数据采集平台)


    最近文章:高可用数据采集平台(如何玩转3门语言php+.net+aauto)高并发数据采集的架构应用(Redis的应用)

    项目文档:关键词匹配项目深入研究(二)- 分表思想的引入

    吐槽:本人也是非常讨厌拿来主义的,有些培训每个细节都提到过,主管还找我要实际案例,而不是去安排合适的人去做这件事情,有点过于拿来主义了,有点担心。

    好消息的是:高并发数据采集的架构应用(Redis的应用)团队已经实现了,不过有部分代码还是我写的,值得喝彩下,说明团队的能力还是不错的。

    最近有时间,我也是用.net完成高可用数据采集平台(如何玩转3门语言php+.net+aauto)服务的编码工作。

    正文开始

    要想快速学习某一件事情,我们就得必须做好规划。

    首先我们先来分析下要实现该项目需要哪些方面的技术,我们从哪里开始分析呢,当然有系统分析师帮你做啦!

    所需的技术

    1. Microsoft Studio 2010 IDE以及.Net Framework基础知识的了解

    2. 如何利用C#创建服务,服务安装以及卸载

    3. SQLite的基础应用以及C#如何使用SQLite

    4. C#定时器的应用

    5. C#的多线程应用以及线程池的应用

    6. 操作系统信号量,互斥同步锁概念以及C#如何使用信号量、互斥同步锁

    7. C#文件操作,ini配置文件读取技术

    8. C# WEB API的调用,以及异步处理知识和C# TASK的了解应用

    9. 数据传输解析技术,以及C#如何解析JSON

    10. 其它常用应用,比如DataSet、DataTable、DataRow、Dictionary、List、KeyValuePair、String等

    这些点看起来好恐怖,要想做好应用这些只是小小的一部分,但相对于菜鸟或者学生们就等于天书了,但是我只有一个星期的事情。

    只要我们有目的去做事,任何事都不会有阻碍,废话少说,等下闲我啰嗦了。

    1. Microsoft Studio 2010 IDE以及.Net Framework基础知识的了解

         这点我竟然列为了重点,有些人有可能对这点不重视,但是我相信很多有经验的人都会同我一样非常重视这点。

        Microsoft Studio 2010 IDE都不用说了,这个大家都是专家,我为什么会选择博客园写文章,是因为我在上学的时候看了一本博客园出版的书,讲的是设计模式的应用,觉得非常的不错,当时博客园是.Net技术平台的佼佼者。

       Microsoft Studio 2010 IDE最主要的一点,就是选择框架,选择项目适合的框架。

       .Net Framework 主要也是注意下为什么有那么多版本,了解下他们互相是否有关系,比如从2.0升到4.0是否能够平稳的过渡。

       2. 如何利用C#创建服务,服务安装以及卸载

        我也是看了一篇博客而学来的,非常不错,我也把地址贴出来:http://www.cnblogs.com/aierong/archive/2012/05/28/2521409.html

       我也是主要用了(a) 利用.net框架类ServiceBase,步骤参考上面博客的地址:安装的时候注意下选择好对应版本的installutil。

        代码贴出来

    public partial class MainService : ServiceBase
        {
            readonly System.Timers.Timer _timer_request;
    
            readonly System.Timers.Timer _timer_upload;
           
            WorkProcess work = new WorkProcess(10);
           
            public MainService()
            {
                InitializeComponent();
    
                //install db table
                TaskModel.install();
    
                _timer_upload  = _timer_request = new System.Timers.Timer(5000)
                {
                    AutoReset = true,
                    Enabled = true
                };
    
                _timer_request.Elapsed += delegate(object sender, ElapsedEventArgs e)
                {
                    Logger.log("Start Request Data From Api");
    
                    try
                    {
                        TaskResponse response = TaskFactory.createFromApi();
                        TaskModel.save(response);
                    }
                    catch (Exception ex)
                    {
                        Logger.error(ex.Message);
                    }
    
                    Logger.log("End Request Data From Api");
                };
    
                _timer_upload.Elapsed += delegate(object sender, ElapsedEventArgs e)
                {
                    Logger.log("Start Upload Data To Api");
                    try
                    {
                        if (!work.wait())
                        {
                            work.doing();
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.error(ex.Message);
                    }
                    Logger.log("End Upload Data To Api");
                   
                };
             
            }
    
            protected override void OnStart(string[] args)
            {
                _timer_request.Enabled = true;
                _timer_upload.Enabled = true;  
            }
    
            protected override void OnStop()
            {
                _timer_request.Enabled = false;
                _timer_upload.Enabled = false;
            }
        }

      

    3. SQLite的基础应用以及C#如何使用SQLite

       也是一样,有博客就是好,推荐代码直接拷贝一份过来。http://www.cnblogs.com/OnlyVersion/p/3746086.html

       我也贴个相对精简的吧。

    class DB
        {
            /// <summary>        
            /// 获得连接对象        
            /// </summary>     
            /// <returns>SQLiteConnection</returns>       
            public static SQLiteConnection GetSQLiteConnection(){
    
                string str = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                var con = new SQLiteConnection("Data Source=" + str + @"" + "DataBase" + @"" + "InfoServiceDb.db");
                return con;       
           }
    
            /// <summary>
            /// 准备操作命令参数
            /// </summary>
            /// <param name="cmd">SQLiteCommand</param>
            /// <param name="conn">SQLiteConnection</param>
            /// <param name="cmdText">Sql命令文本</param>
            /// <param name="data">参数数组</param>
            private static void PrepareCommand(SQLiteCommand cmd, SQLiteConnection conn, string cmdText, Dictionary<String, String> data)
            {
                if (conn.State != ConnectionState.Open)
                    conn.Open();
                cmd.Parameters.Clear();
                cmd.Connection = conn;
                cmd.CommandText = cmdText;
                cmd.CommandType = CommandType.Text;
                cmd.CommandTimeout = 30;
                if (data != null && data.Count >= 1)
                {
                    foreach (KeyValuePair<String, String> val in data)
                    {
                        cmd.Parameters.AddWithValue(val.Key, val.Value);
                    }
                }
            }
    
            /// <summary>
            /// 查询,返回DataSet
            /// </summary>
            /// <param name="cmdText">Sql命令文本</param>
            /// <param name="data">参数数组</param>
            /// <returns>DataSet</returns>
            public static DataSet ExecuteDataset(string cmdText, Dictionary<string, string> data)
            {
                var ds = new DataSet();
                using (SQLiteConnection connection = GetSQLiteConnection())
                {
                    var command = new SQLiteCommand();
                    PrepareCommand(command, connection, cmdText, data);
                    var da = new SQLiteDataAdapter(command);
                    da.Fill(ds);
                }
                return ds;
            }
    
            /// <summary>
            /// 查询,返回DataTable
            /// </summary>
            /// <param name="cmdText">Sql命令文本</param>
            /// <param name="data">参数数组</param>
            /// <returns>DataTable</returns>
            public static DataTable ExecuteDataTable(string cmdText, Dictionary<string, string> data)
            {
                var dt = new DataTable();
                using (SQLiteConnection connection = GetSQLiteConnection())
                {
                    var command = new SQLiteCommand();
                    PrepareCommand(command, connection, cmdText, data);
                    SQLiteDataReader reader = command.ExecuteReader();
                    dt.Load(reader);
                }
                return dt;
            }
    
            /// <summary>
            /// 返回一行数据
            /// </summary>
            /// <param name="cmdText">Sql命令文本</param>
            /// <param name="data">参数数组</param>
            /// <returns>DataRow</returns>
            public static DataRow ExecuteDataRow(string cmdText, Dictionary<string, string> data)
            {
                DataSet ds = ExecuteDataset(cmdText, data);
                if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
                    return ds.Tables[0].Rows[0];
                return null;
            }
    
            /// <summary>
            /// 执行数据库操作
            /// </summary>
            /// <param name="cmdText">Sql命令文本</param>
            /// <param name="data">传入的参数</param>
            /// <returns>返回受影响的行数</returns>
            public static int ExecuteNonQuery(string cmdText, Dictionary<string, string> data)
            {
                using (SQLiteConnection connection = GetSQLiteConnection())
                {
                    var command = new SQLiteCommand();
                    PrepareCommand(command, connection, cmdText, data);
                    return command.ExecuteNonQuery();
                }
            }
    
            /// <summary>
            /// 返回SqlDataReader对象
            /// </summary>
            /// <param name="cmdText">Sql命令文本</param>
            /// <param name="data">传入的参数</param>
            /// <returns>SQLiteDataReader</returns>
            public static SQLiteDataReader ExecuteReader(string cmdText, Dictionary<string, string> data)
            {
                var command = new SQLiteCommand();
                SQLiteConnection connection = GetSQLiteConnection();
                try
                {
                    PrepareCommand(command, connection, cmdText, data);
                    SQLiteDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
                    return reader;
                }
                catch
                {
                    connection.Close();
                    command.Dispose();
                    throw;
                }
            }
    
            /// <summary>
            /// 返回结果集中的第一行第一列,忽略其他行或列
            /// </summary>
            /// <param name="cmdText">Sql命令文本</param>
            /// <param name="data">传入的参数</param>
            /// <returns>object</returns>
            public static object ExecuteScalar(string cmdText, Dictionary<string, string> data)
            {
                using (SQLiteConnection connection = GetSQLiteConnection())
                {
                    var cmd = new SQLiteCommand();
                    PrepareCommand(cmd, connection, cmdText, data);
                    return cmd.ExecuteScalar();
                }
            }
    }

    4. C#定时器的应用

      参考1.创建服务的代码

      主要两个定时器:

             1. 用于请求服务端要待处理事项

             2. 用于上传已处理事项的数据到服务器。

    5. C#的多线程应用以及线程池的应用

         多线程和线程池的概念这儿略过,本次应用只使用了.Net Framework中提供ThreadPool

        ThreadPool:http://www.cnblogs.com/xugang/archive/2010/04/20/1716042.html ,这篇博客很好的介绍了基础知识。

        我也贴一下,本次应用的代码:

    public class WorkProcess
        {
            public static int iCount = 0;
            public static int iMaxCount = 0;
    
            public WorkProcess(int MaxCount)
            {
                iMaxCount = MaxCount;
            }
    
            //线程池里的线程将调用Beta()方法
            public void execute(Object state)
            {
                Interlocked.Increment(ref iCount);
                try
                {
                    TaskState taskState = (TaskState)state;
                    string lockedStr = string.Format("task.locked.{0}.{1}", taskState.taskId, taskState.uploadId);
    
                    lock (lockedStr)
                    {
                        TaskUpload.work(taskState);
                    }
                    int iX = 10000;
                    Thread.Sleep(iX);
                }
                catch (Exception e)
                {
                    Logger.error(e.Message);
                }
                finally
                {
                    Interlocked.Decrement(ref iCount);
                }
               
            }
    
            public bool wait()
            {
                 int threadNumber = 0;  
                //获取当前线程数  
                 threadNumber = Interlocked.Exchange(ref iCount, iCount);
    
                 Logger.log(string.Format("Thread Num:{0}",threadNumber));
    
                 if (threadNumber <= iMaxCount)
                 {
                     return false;
                 }
                 return true;
    
            }
    
            public void doing()
            {
                string sql = "SELECT task.id as id,task_upload.id as uploadId FROM task LEFT JOIN task_upload ON task.id=task_upload.task_id WHERE status=:status AND upload_status=:upload_status LIMIT 10";
                Dictionary<string, string> data = new Dictionary<string, string>();
                data.Add(":status", "DONE");
                data.Add(":upload_status", "WAIT");
                DataTable dt = DB.ExecuteDataTable(sql, data);
    
                foreach (DataRow row in dt.Rows)
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(this.execute), new TaskState((int)row["id"], (int)row["uploadId"]));
                }  
            }
        }

    6. 操作系统信号量,互斥同步锁概念以及C#如何使用信号量、互斥同步锁

       本次应用使用了信号量,主要作用是防止无限制的往线程池里面PUSH任务,适当的等待下任务的处理进度。

    7. C#文件操作,ini配置文件读取技术

        本次应用主要使用文件存储一些必要的调试信息以及错误信息。

    public class Logger
        {
            private static readonly string ErrorFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"" +"logs"+@""+ "error.txt";
            private static readonly string LogFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"" + "logs" + @"" + "log.txt";
            
            public static void log(string msg)
            {
                StreamWriter sw = File.AppendText(LogFileName);
                sw.WriteLine(string.Format("{0}:{1}",DateTime.Now,msg));
                sw.Flush();
                sw.Close();
            }
    
            public static void error(string msg)
            {
                StreamWriter sw = File.AppendText(ErrorFileName);
                sw.WriteLine(string.Format("{0}:{1}", DateTime.Now, msg));
                sw.Flush();
                sw.Close();
            }
        }

    Ini配置读取是为了更好的成为一个独立的构件,源码来源博客园的其他作者。

    /// <summary>
        /// IniFiles的类
        /// </summary>
        public class IniFiles
        {
            public string FileName; //INI文件名
            //声明读写INI文件的API函数
            [DllImport("kernel32")]
            private static extern bool WritePrivateProfileString(string section, string key, string val, string filePath);
            [DllImport("kernel32")]
            private static extern int GetPrivateProfileString(string section, string key, string def, byte[] retVal, int size, string filePath);
    
            public static IniFiles config(){
    
                string configFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)+@"config.ini";
    
                return new IniFiles(configFileName);
            }
    
            //类的构造函数,传递INI文件名
            public IniFiles(string AFileName)
            {
                // 判断文件是否存在
                FileInfo fileInfo = new FileInfo(AFileName);
                //Todo:搞清枚举的用法
                if ((!fileInfo.Exists))
                { //|| (FileAttributes.Directory in fileInfo.Attributes))
                    //文件不存在,建立文件
                    System.IO.StreamWriter sw = new System.IO.StreamWriter(AFileName, false, System.Text.Encoding.Default);
                    try
                    {
                        sw.Write("#表格配置档案");
                        sw.Close();
                    }
                    catch
                    {
                        throw (new ApplicationException("Ini文件不存在"));
                    }
                }
                //必须是完全路径,不能是相对路径
                FileName = fileInfo.FullName;
            }
            //写INI文件
            public void WriteString(string Section, string Ident, string Value)
            {
                if (!WritePrivateProfileString(Section, Ident, Value, FileName))
                {
                    throw (new ApplicationException("写Ini文件出错"));
                }
            }
            //读取INI文件指定
            public string ReadString(string Section, string Ident, string Default)
            {
                Byte[] Buffer = new Byte[65535];
                int bufLen = GetPrivateProfileString(Section, Ident, Default, Buffer, Buffer.GetUpperBound(0), FileName);
                //必须设定0(系统默认的代码页)的编码方式,否则无法支持中文
                string s = Encoding.GetEncoding(0).GetString(Buffer);
                s = s.Substring(0, bufLen);
                return s.Trim();
            }
     
            //读整数
            public int ReadInteger(string Section, string Ident, int Default)
            {
                string intStr = ReadString(Section, Ident, Convert.ToString(Default));
                try
                {
                    return Convert.ToInt32(intStr);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return Default;
                }
            }
     
            //写整数
            public void WriteInteger(string Section, string Ident, int Value)
            {
                WriteString(Section, Ident, Value.ToString());
            }
     
            //读布尔
            public bool ReadBool(string Section, string Ident, bool Default)
            {
                try
                {
                    return Convert.ToBoolean(ReadString(Section, Ident, Convert.ToString(Default)));
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return Default;
                }
            }
     
            //写Bool
            public void WriteBool(string Section, string Ident, bool Value)
            {
                WriteString(Section, Ident, Convert.ToString(Value));
            }
     
            //从Ini文件中,将指定的Section名称中的所有Ident添加到列表中
            public void ReadSection(string Section, StringCollection Idents)
            {
                Byte[] Buffer = new Byte[16384];
                //Idents.Clear();
     
                int bufLen = GetPrivateProfileString(Section, null, null, Buffer, Buffer.GetUpperBound(0),
                      FileName);
                //对Section进行解析
                GetStringsFromBuffer(Buffer, bufLen, Idents);
            }
     
            private void GetStringsFromBuffer(Byte[] Buffer, int bufLen, StringCollection Strings)
            {
                Strings.Clear();
                if (bufLen != 0)
                {
                    int start = 0;
                    for (int i = 0; i < bufLen; i++)
                    {
                        if ((Buffer[i] == 0) && ((i - start) > 0))
                        {
                            String s = Encoding.GetEncoding(0).GetString(Buffer, start, i - start);
                            Strings.Add(s);
                            start = i + 1;
                        }
                    }
                }
            }
            //从Ini文件中,读取所有的Sections的名称
            public void ReadSections(StringCollection SectionList)
            {
                //Note:必须得用Bytes来实现,StringBuilder只能取到第一个Section
                byte[] Buffer = new byte[65535];
                int bufLen = 0;
                bufLen = GetPrivateProfileString(null, null, null, Buffer,
                 Buffer.GetUpperBound(0), FileName);
                GetStringsFromBuffer(Buffer, bufLen, SectionList);
            }
            //读取指定的Section的所有Value到列表中
            public void ReadSectionValues(string Section, NameValueCollection Values)
            {
                StringCollection KeyList = new StringCollection();
                ReadSection(Section, KeyList);
                Values.Clear();
                foreach (string key in KeyList)
                {
                    Values.Add(key, ReadString(Section, key, ""));
                }
            }
            ////读取指定的Section的所有Value到列表中,
            //public void ReadSectionValues(string Section, NameValueCollection Values,char splitString)
            //{  string sectionValue;
            //  string[] sectionValueSplit;
            //  StringCollection KeyList = new StringCollection();
            //  ReadSection(Section, KeyList);
            //  Values.Clear();
            //  foreach (string key in KeyList)
            //  {
            //    sectionValue=ReadString(Section, key, "");
            //    sectionValueSplit=sectionValue.Split(splitString);
            //    Values.Add(key, sectionValueSplit[0].ToString(),sectionValueSplit[1].ToString());
     
            //  }
            //}
            //清除某个Section
            public void EraseSection(string Section)
            {
                if (!WritePrivateProfileString(Section, null, null, FileName))
                {
                    throw (new ApplicationException("无法清除Ini文件中的Section"));
                }
            }
            //删除某个Section下的键
            public void DeleteKey(string Section, string Ident)
            {
                WritePrivateProfileString(Section, Ident, null, FileName);
            }
            //Note:对于Win9X,来说需要实现UpdateFile方法将缓冲中的数据写入文件
            //在Win NT, 2000和XP上,都是直接写文件,没有缓冲,所以,无须实现UpdateFile
            //执行完对Ini文件的修改之后,应该调用本方法更新缓冲区。
            public void UpdateFile()
            {
                WritePrivateProfileString(null, null, null, FileName);
            }
     
            //检查某个Section下的某个键值是否存在
            public bool ValueExists(string Section, string Ident)
            {
                StringCollection Idents = new StringCollection();
                ReadSection(Section, Idents);
                return Idents.IndexOf(Ident) > -1;
            }
     
            //确保资源的释放
            ~IniFiles()
            {
                UpdateFile();
            }
        }

    我们也是主要学习下使用方式就好了。

    8. C# WEB API的调用,以及异步处理知识和C# TASK的了解应用

        C# WEB API的调用也是参考了博客园的知识:http://www.cnblogs.com/r01cn/archive/2012/11/20/2779011.html

        主要也是使用了HttpClient。

        代码如下:

    public static TaskResponse createFromApi()
            {
                HttpClient client = new HttpClient();
                client.DefaultRequestHeaders.Accept.Add(
                   new MediaTypeWithQualityHeaderValue("application/json")
                 );
                string readUri = IniFiles.config().ReadString("uri","read","");      
                HttpResponseMessage response = client.GetAsync(readUri).Result;
    
                if (response.IsSuccessStatusCode)
                {
                    // Parse the response body. Blocking!
                    var taskString = response.Content.ReadAsStringAsync().Result;
                  
                    StringReader sr = new StringReader(taskString.ToString());
                    JsonSerializer serializer = new JsonSerializer();
                    TaskResponse taskResponse = (TaskResponse)serializer.Deserialize(new JsonTextReader(sr),typeof(TaskResponse));
                   
                    Logger.log(string.Format("nick:{0},Type:{1}", taskResponse.nick, taskResponse.type));
                    return taskResponse;               
                }
                else
                {
                    Logger.error(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
                    throw new Exception(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
                }
            }
    
            public static bool upload(string jsonData)
            {
                HttpClient client = new HttpClient();
                client.DefaultRequestHeaders.Accept.Add(
                   new MediaTypeWithQualityHeaderValue("application/json")
                 );
    
                string uploadUri = IniFiles.config().ReadString("uri", "upload", "");
                List<KeyValuePair<String, String>> paramList = new List<KeyValuePair<String, String>>();
                paramList.Add(new KeyValuePair<string, string>("data",jsonData));
    
                var response = client.PostAsync(uploadUri, new FormUrlEncodedContent(paramList)).Result;
                if (response.IsSuccessStatusCode)
                {
                    var responseString = response.Content.ReadAsStringAsync().Result;
                    Logger.log(responseString.ToString());
                    return true;
                }
                else
                {
                    Logger.error(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
                    return false;
                }
    
            }

    9. 数据传输解析技术,以及C#如何解析JSON

       数据传输技术已经经历过很多时代,不过现在的时代用json还是相当比较普及的,比如现在的手机行业的普及,JSON的传输方式再一次被推向浪的高潮。

      C# json解析,我使用了第三方包Newtonsoft.Json,原因很简单,我觉得易用,哪个好用我就选哪个。

      使用方法参考 8.C# WEB API的调用,以及异步处理知识和C# TASK的了解应用

    10. 其它常用应用,比如DataSet、DataTable、DataRow、Dictionary、List、KeyValuePair、String等

         因为这些是基础,多使用,摸清他们的关系,基本讲求到会用就行了,当然性能优化的另说了,你要纠结的话那就去纠结吧。

    总结:

         要想成功做好一件事情,是要有目的的去做去学,像我这样能把所有的都列清楚,一步一步的走吧,相信你离成功将会不远了。

  • 相关阅读:
    BottomNavigationBarItem fixed
    Flutter进阶—点击、拖动和其他手势
    semaphore demo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
    微信小程序
    Socket套接字 =======================
    socket
    flutter packages.
    安卓抓包https
    Flutter 输入控件TextField设置内容并保持光标(cursor)在末尾
    textfield reload issue and other things reload problem.===================================
  • 原文地址:https://www.cnblogs.com/oshine/p/4214665.html
Copyright © 2020-2023  润新知