Net5 WorkService 繼承 Quarzt 及 Net5處理文件上傳功能

Net5 版本以Core為底層非framework框架的windowservice 服務。

在VS裡叫WorkService 可以以CMD方式運行也可以以Windowservice方式運行,部署簡單。

Program.cs如下,是關鍵配置和啟動項

using Microsoft.Extensions.Hosting;
using Quartz;
using WorkerService.Common;
using WorkerService.Job;
namespace WorkerService
{
    public class Program
    {
        public static void Main(string[] args)
        {
            
            CreateHostBuilder(args).Build().Run();
        }
    
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args).UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                    #region  原生work Service
                    //自定義調度
                    //services.AddHostedService<Worker>();
                    #endregion
                    #region quartz 原始版本
                    //這個版本    trigger  job Schedule 是唯一關聯,不能一個組下多個任務
                    //services.AddQuartz(q =>
                    //{
                    //    q.UseMicrosoftDependencyInjectionScopedJobFactory();
                    //    // Create a "key" for the job
                    //    var jobKey = new JobKey("HelloTestJob");
                    //    // Register the job with the DI container
                    //    q.AddJob<HelloTestJob>(opts => opts.WithIdentity(jobKey));
                    //    // Create a trigger for the job
                    //    q.AddTrigger(opts => opts
                    //        .ForJob(jobKey) // link to the HelloWorldJob
                    //        .WithIdentity("HelloTestJob-trigger") // give the trigger a unique name
                    //        .WithCronSchedule("0/1 * * * * ?")); // run every 1 seconds
                    //});
                    //services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
                    #region quarzt 優化版本
                    //    // Register the job, loading the schedule from configuration
                    //    q.AddJobAndTrigger<HelloTestJob>(hostContext.Configuration, "0/1 * * * * ?");//每秒運行一次
                    //    q.AddJobAndTrigger<HelloTestJob2>(hostContext.Configuration, "0/1 * * * * ?");
                    #region  溫濕度 SF6 紅外圖片上傳
             
                    services.AddQuartz(q =>
                    {
                        q.UseMicrosoftDependencyInjectionScopedJobFactory();
                        //每秒 0/1 * * * * ?   每小時  0 0 * * * ?
                        // Register the job, loading the schedule from configuration
                        q.AddJobAndTrigger<TemperatureJob>(hostContext.Configuration, "0 0 * * * ?");
                        q.AddJobAndTrigger<SF6Job>(hostContext.Configuration, "0 0 * * * ?");
                        q.AddJobAndTrigger<InfraredJob>(hostContext.Configuration, "0 0 * * * ?");
                    });
                    services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
                });
    }
   
}

原始的Host.CreateDefaultBuilder(args) 需要增加 .UseWindowsService() 支持 對windowservice

quarzt 在 NET5的nuget 中叫Quartz.Extensions.Hosting

services.AddHostedService<Worker>(); 是原始的windows定時任務版本

代碼如下, 在await Task.Delay(1000, stoppingToken); 設定定時啟動的毫秒數就可以瞭

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace WorkerService.Job.Test
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                FileStream stream = new FileStream(@"d:\aa.txt", FileMode.Create);//fileMode指定是讀取還是寫入
                StreamWriter writer = new StreamWriter(stream);
                writer.WriteLine("123456"+ DateTimeOffset.Now);//寫入一行,寫完後會自動換行
                writer.Write("abc");//寫完後不會換行
                writer.WriteLine("ABC");
                writer.Close();//釋放內存
                stream.Close();//釋放內存
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

quartz 原始版本(program.cs代碼截圖)

在目前這個quartz 3.3.3 版本中好像不能一個Key 下多個Job集成作業。所以每個job需要一個一個註冊。推薦使用優化版本

quarzt 優化版本(program.cs代碼截圖)

對原始版本進行瞭封裝。在每一次調用的時候會註冊新的唯一實例。

以下是幫助類

using Microsoft.Extensions.Configuration;
using Quartz;
using System;
namespace WorkerService.Common
{
    public static class ServiceCollectionQuartzConfiguratorExtensions
    {
        public static void AddJobAndTrigger<T>(
            this IServiceCollectionQuartzConfigurator quartz,
            IConfiguration config, string cronSchedule)
            where T : IJob
        {
            // Use the name of the IJob as the appsettings.json key
            string jobName = typeof(T).Name;
            // Try and load the schedule from configuration
            var configKey = $"Quartz:{jobName}";
            //var cronSchedule = config[configKey];
            // Some minor validation
            if (string.IsNullOrEmpty(cronSchedule))
            {
                throw new Exception($"No Quartz.NET Cron schedule found for job in configuration at {configKey}");
            }
            // register the job as before
            var jobKey = new JobKey(jobName);
            quartz.AddJob<T>(opts => opts.WithIdentity(jobKey));
            quartz.AddTrigger(opts => opts
                .ForJob(jobKey)
                .WithIdentity(jobName + "-trigger")
                .WithCronSchedule(cronSchedule)); // use the schedule from configuration
        }
    }
}

以下是Job

using Microsoft.Extensions.Logging;
using Quartz;
using System;
using System.IO;
using System.Threading.Tasks;
namespace WorkerService.Job.Test
{
    [DisallowConcurrentExecution]
    public class HelloTestJob2 : IJob
    {
        private readonly ILogger<HelloTestJob2> _logger;
        public HelloTestJob2(ILogger<HelloTestJob2> logger)
        {
            _logger = logger;
        }
        public Task Execute(IJobExecutionContext context)
        {
            FileStream stream = new FileStream(@"d:\aa1.txt", FileMode.Create);//fileMode指定是讀取還是寫入
            StreamWriter writer = new StreamWriter(stream);
            writer.WriteLine("123456aaa" + DateTimeOffset.Now);//寫入一行,寫完後會自動換行
            writer.Write("abc");//寫完後不會換行
            writer.WriteLine("ABC");
            writer.Close();//釋放內存
            stream.Close();//釋放內存
            return Task.CompletedTask;
        }
    }
}

程序會根據Corn 設定的運行時間定期在Task Execute(IJobExecutionContext context)方法內運行

然後就是蠻搞笑的,大夥都不用Net5 嗎。寫服務上傳文件。遇到問題搜索NET5處理文件上傳問題,居然都是空白的。 那我就隻好自己寫解決方案瞭。

客戶端圖片上傳的HTTPHelper.cs部分代碼如下

/// <summary>
        /// 上傳文件
        /// </summary>
        /// <param name="url">請求地址</param>
        /// <param name="path">文件路徑(帶文件名)</param>
        /// <returns></returns>
        public static string HttpPostFile(string url, string path)
        {
            // 設置參數
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            CookieContainer cookieContainer = new CookieContainer();
            request.CookieContainer = cookieContainer;
            request.AllowAutoRedirect = true;
            request.Method = "POST";string boundary = DateTime.Now.Ticks.ToString("X"); // 隨機分隔線
            request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;
            byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
            int pos = path.LastIndexOf("\\");
            string fileName = path.Substring(pos + 1);
            //請求頭部信息
            StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\nContent-Type:application/octet-stream\r\n\r\n", fileName));
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());
            StringBuilder builder = new StringBuilder($"Content-Disposition:form-data;name=\"subPath\"\r\n\r\ntmswechat");
            byte[] postHeaderBytestwo = Encoding.UTF8.GetBytes(builder.ToString());
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            byte[] bArr = new byte[fs.Length];
            fs.Read(bArr, 0, bArr.Length);
            fs.Close();
            Stream postStream = request.GetRequestStream();
            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
            postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
            postStream.Write(bArr, 0, bArr.Length);
            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
            postStream.Write(postHeaderBytestwo, 0, postHeaderBytestwo.Length);
            postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
            postStream.Close();
            //發送請求並獲取相應回應數據
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            //直到request.GetResponse()程序才開始向目標網頁發送Post請求
            Stream instream = response.GetResponseStream();
            StreamReader sr = new StreamReader(instream, Encoding.UTF8);
            //返回結果網頁(html)代碼
            string content = sr.ReadToEnd();
            return content;
        }

重點是服務端的接收,部分代碼如下

try
                    {
                    var files = Request.Form.Files;
                    if (files != null)
                    {
                        var file = files[0];
                
                        var location = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + $"Image\\" + file.FileName;
                        if (!Directory.Exists(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + $"Image\\")) //判斷上傳文件夾是否存在,若不存在,則創建
                        {
                            Directory.CreateDirectory(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + $"Image\\"); //創建文件夾
                        }
                        using (var stream = new FileStream(location, FileMode.Create))
                        {
                            await file.CopyToAsync(stream);
                            result = 1;
                        }
                    }
                    //using (var reader = new StreamReader(Request.Body))//從身體裡讀取
                    //{
                    //    var body = await reader.ReadToEndAsync(); 
                      
                    //}
                    }
                    catch (Exception e )
                    {
                        throw;
                    }

哪怕你用的是文件流上傳,不是表單提交。但是你的文件依舊在Request.Form.Files 裡!!!!

但你也可以通過Request.body 讀到流

//using (var reader = new StreamReader(Request.Body))//從身體裡讀取
//{

// var body = await reader.ReadToEndAsync();

//}

到此這篇關於Net5 WorkService 繼承 Quarzt 以及 Net5處理文件上傳的文章就介紹到這瞭,更多相關Net5 WorkService 繼承 Quarzt 內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: