C# WinFrom+AspNetCore WebApi实现大文件下载与上传

客户端UI:

服务端WebApi:

客户端代码:

App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<appSettings>
		<add key="WebApi" value="https://localhost:7285"/>
		<add key="SavePath" value="E:\Down"/>
		<add key="DownFileName" value="win11x64.esd"/>
		<add key="UploadFileName" value="win11x64.esd"/>
	</appSettings>
</configuration>

自定义进度条:

CustomProgressBar.cs(长方形)

using System;
using System.Windows.Forms;
using System.Drawing;

namespace FileUploadAndDown
{
    public class CustomProgressBar : ProgressBar
    {
        // 添加一个属性来存储速率文本
        public string RateText { get; set; } = "0 KB/s";

        public CustomProgressBar()
        {
            // 设置样式以允许重绘。
            this.SetStyle(ControlStyles.UserPaint, true);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Rectangle rect = this.ClientRectangle;
            Graphics g = e.Graphics;

            ProgressBarRenderer.DrawHorizontalBar(g, rect);
            rect.Inflate(-3, -3); // 减小大小以适应边界
            if (this.Value > 0)
            {
                Rectangle clip = new Rectangle(rect.X, rect.Y, (int)Math.Round(((float)this.Value / this.Maximum) * rect.Width), rect.Height);
                g.FillRectangle(Brushes.GreenYellow, clip);
            }

            string text = this.Value.ToString() + "%";
            using (Font f = new Font(FontFamily.GenericSansSerif, 10))
            {
                SizeF len = g.MeasureString(text, f);
                Point location = new Point((int)((rect.Width / 2) - (len.Width / 2)), (int)((rect.Height / 2) - (len.Height / 2)));
                g.DrawString(text, f, Brushes.Black, location);

                // 绘制速率文本
                SizeF rateLen = g.MeasureString(RateText, f);
                Point rateLocation = new Point(rect.Right - (int)rateLen.Width - 5, (int)((rect.Height / 2) - (rateLen.Height / 2)));
                g.DrawString(RateText, f, Brushes.Black, rateLocation);
            }
        }
    }
}

自定义圆型进度条:

CircularProgressBar.cs

using System;
using System.Drawing;
using System.Windows.Forms;

namespace FileUploadAndDown
{
    public class CircularProgressBar : UserControl
    {
        private int progress = 0;
        private int max = 100;

        public int Progress
        {
            get { return progress; }
            set
            {
                progress = value;
                this.Invalidate(); // 通知控件需要重绘
            }
        }

        public int Maximum
        {
            get { return max; }
            set
            {
                max = value;
                this.Invalidate(); // 通知控件需要重绘
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            // 绘制外圈
            g.DrawEllipse(Pens.Black, 0, 0, this.Width - 1, this.Height - 1);

            // 计算进度
            float sweepAngle = 360f * progress / max;

            // 绘制进度
            using (Brush brush = new SolidBrush(Color.Blue))
            {
                g.FillPie(brush, 0, 0, this.Width, this.Height, -90, sweepAngle);
            }

            // 绘制中心覆盖圆,形成环形进度条
            int coverSize = 20; // 中心圆的大小,可以根据需要调整
            using (Brush brush = new SolidBrush(this.BackColor))
            {
                g.FillEllipse(brush, (this.Width - coverSize) / 2, (this.Height - coverSize) / 2, coverSize, coverSize);
            }
        }
    }
}


HttpContent.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace FileUploadAndDown
{
    public class ProgressableStreamContent : HttpContent
    {
        private readonly HttpContent content;
        private readonly int bufferSize = 4096;
        private readonly Action<long, long> progress;

        public ProgressableStreamContent(HttpContent content, Action<long, long> progress)
        {
            this.content = content ?? throw new ArgumentNullException(nameof(content));
            this.progress = progress ?? throw new ArgumentNullException(nameof(progress));

            foreach (var header in content.Headers)
            {
                this.Headers.TryAddWithoutValidation(header.Key, header.Value);
            }
        }

        protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            var buffer = new byte[bufferSize];
            TryComputeLength(out long size);
            var uploaded = 0L;

            using (var contentStream = await content.ReadAsStreamAsync())
            {
                var read = 0;
                while ((read = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await stream.WriteAsync(buffer, 0, read);
                    uploaded += read;
                    progress(uploaded, size);
                }
            }
        }

        protected override bool TryComputeLength(out long length)
        {
            length = content.Headers.ContentLength ?? -1;
            return length != -1;
        }
    }
}

ServerResponse.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FileUploadAndDown
{
    public class ServerResponse
    {
        public int Code { get; set; }
        public string Message { get; set; }
        public FileListData Data { get; set; }
    }

    public class FileListData
    {
        public List<string> Files { get; set; }
    }

}

MainWinFrm.cs

using System;
using System.IO;
using System.Net.Http;
using System.Windows.Forms;
using System.Threading.Tasks;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using System.Configuration;
using static System.Net.WebRequestMethods;

namespace FileUploadAndDown
{
    public partial class MainWinFrm : Form
    {
        private HttpClient _httpClient = new HttpClient();
        public List<string> fileInfos = new List<string>();

        /// <summary>
        /// 保存文件路径
        /// </summary>
        public string? SavePath { get; set; }

        /// <summary>
        /// 下载文件名称
        /// </summary>
        public string? DownFileName { get; set; }

        /// <summary>
        /// 上传文件名称
        /// </summary>
        public string? UploadFileName { get; set; }

        /// <summary>
        /// WebApi接口
        /// </summary>
        public string? WebApi { get; set; }

        public MainWinFrm()
        {
            InitializeComponent();

            //读取配置信息
            this.WebApi = ConfigurationManager.AppSettings["WebApi"]!;
            this.SavePath = ConfigurationManager.AppSettings["SavePath"]!;
            this.DownFileName = ConfigurationManager.AppSettings["DownFileName"]!;
            this.UploadFileName = ConfigurationManager.AppSettings["UploadFileName"]!;

            _httpClient = new HttpClient
            {
                Timeout = TimeSpan.FromMinutes(10) // 设置超时时间为10分钟
            };
            // 初始化进度条
            InitializeUI();
        }

        private void InitializeUI()
        {
            // 设置进度条属性
            progressBar.Minimum = 0;
            progressBar.Maximum = 100;
            progressBar.Value = 0;

            FetchDownloadableFiles();//获取所有文件
        }

        #region 上传文件
        private async void btn_Upload_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string filePath = openFileDialog.FileName;
                await UploadFile(filePath);
            }
        }
        #endregion

        #region 下载
        private async void btn_Dwon_Click(object sender, EventArgs e)
        {
            // 这里可以使用fileInfos列表让用户选择要下载的文件,例如通过一个下拉菜单
            if (fileInfos == null || fileInfos.Count == 0)
            {
                MessageBox.Show("No files available for download.");
                return;
            }

            string fileName = fileInfos[0]; // 假设用户选择了列表中的第一个文件
            await DownloadFile(fileName);
        }


        #endregion

        #region 上传
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="filePath">上传文件路径及名称</param>
        /// <returns></returns>
        private async Task UploadFile(string filePath)
        {
            var fileInfo = new FileInfo(filePath);
            var fileContent = new StreamContent(System.IO.File.OpenRead(filePath));
            var content = new MultipartFormDataContent
    {
        { fileContent, "file", fileInfo.Name }
    };

            var lastUpdateTime = DateTime.Now; // 用于跟踪上次更新时间
            var lastReportedProgress = -1; // 用于跟踪上次报告的进度
            long lastUploadedBytes = 0; // 上次上传的字节数

            var progressContent = new ProgressableStreamContent(content, (uploaded, total) =>
            {
                var now = DateTime.Now;
                var timeSpan = now - lastUpdateTime;
                if (timeSpan.TotalSeconds >= 1) // 每秒更新一次速率
                {
                    var rate = (uploaded - lastUploadedBytes) / timeSpan.TotalSeconds / 1024; // 速率 KB/s
                    lastUpdateTime = now;
                    lastUploadedBytes = uploaded;

                    var progressPercentage = (int)((uploaded * 100) / total);
                    if (Math.Abs(progressPercentage - lastReportedProgress) >= 1)
                    {
                        lastReportedProgress = progressPercentage;
                        Invoke((MethodInvoker)delegate
                        {
                            progressBar.Value = progressPercentage;
                            progressBar.RateText = $"{rate:0.00} KB/s"; // 更新速率信息
                            lblProgress.Text = $"{progressPercentage}%"; // 更新进度标签
                        });
                    }
                }
            });

            var response = await _httpClient.PostAsync($@"{this.WebApi}/Files/upload", progressContent);
            if (response.IsSuccessStatusCode)
            {
                Invoke((MethodInvoker)delegate
                {
                    MessageBox.Show("File uploaded successfully.");
                });
            }
            else
            {
                Invoke((MethodInvoker)delegate
                {
                    MessageBox.Show($"Upload failed: {response.ReasonPhrase}");
                });
            }
        }



        #endregion

        #region 下载
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="fileName">下载文件名称</param>
        /// <param name="savePath">下载文件保存路径</param>
        /// <returns></returns>
        private async Task DownloadFile(string fileName)
        {
            var response = await _httpClient.GetAsync($"{this.WebApi}/Files/download/{fileName}", HttpCompletionOption.ResponseHeadersRead);

            if (response.IsSuccessStatusCode)
            {
                var saveFilePath = Path.Combine(SavePath, fileName);

                using (var stream = await response.Content.ReadAsStreamAsync())
                using (var fileStream = new FileStream(saveFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    var totalRead = 0L;
                    var totalReadBytes = response.Content.Headers.ContentLength ?? 0;
                    var buffer = new byte[4096];
                    var isMoreToRead = true;
                    var lastReportedProgress = -1; // 用于跟踪上次报告的进度
                    var lastUpdateTime = DateTime.Now; // 用于跟踪上次更新时间
                    long lastDownloadedBytes = 0; // 上次下载的字节数

                    do
                    {
                        var read = await stream.ReadAsync(buffer, 0, buffer.Length);
                        if (read == 0)
                        {
                            isMoreToRead = false;
                        }
                        else
                        {
                            await fileStream.WriteAsync(buffer, 0, read);
                            totalRead += read;
                            var progress = (int)((totalRead * 100) / totalReadBytes);

                            var now = DateTime.Now;
                            var timeSpan = now - lastUpdateTime;
                            if (timeSpan.TotalSeconds >= 1) // 每秒更新一次速率
                            {
                                var rate = (totalRead - lastDownloadedBytes) / timeSpan.TotalSeconds / 1024; // 速率 KB/s
                                lastUpdateTime = now;
                                lastDownloadedBytes = totalRead;

                                // 仅当进度有显著变化时才更新 UI
                                if (Math.Abs(progress - lastReportedProgress) >= 1) // 这里的 1 表示至少有 1% 的变化
                                {
                                    lastReportedProgress = progress;
                                    Invoke((MethodInvoker)delegate
                                    {
                                        progressBar.Value = progress;
                                        progressBar.RateText = $"{rate:0.00} KB/s"; // 更新速率信息
                                        lblProgress.Text = $"{progress}%"; // 更新进度标签
                                    });
                                }
                            }
                        }
                    } while (isMoreToRead);
                }

                Invoke((MethodInvoker)delegate
                {
                    MessageBox.Show($"File downloaded successfully and saved as {saveFilePath}.");
                });
            }
            else
            {
                Invoke((MethodInvoker)delegate
                {
                    MessageBox.Show($"Download failed: {response.ReasonPhrase}");
                });
            }
        }



        #endregion


        // 新增方法:获取服务器上可下载的文件列表
        #region 获取所有文件信息
        private async void FetchDownloadableFiles()
        {
            try
            {
                var response = await _httpClient.GetAsync($"{this.WebApi}/Files/list");
                if (response.IsSuccessStatusCode)
                {
                    var jsonString = await response.Content.ReadAsStringAsync();
                    var serverResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<ServerResponse>(jsonString);

                    if (serverResponse != null && serverResponse.Data != null && serverResponse.Data.Files != null)
                    {
                        this.fileInfos = serverResponse.Data.Files;

                        // 更新UI,例如使用ComboBox或ListBox展示文件列表
                        // 注意:此处更新UI的代码应该在UI线程上执行,可能需要使用Invoke或BeginInvoke方法
                    }
                }
                else
                {
                    MessageBox.Show("Failed to fetch files list.");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error fetching files list: {ex.Message}");
            }
        }

        #endregion
    }
}

MainWinFrm.Designer.cs

namespace FileUploadAndDown
{
    partial class MainWinFrm
    {
        /// <summary>
        ///  Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        ///  Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        ///  Required method for Designer support - do not modify
        ///  the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            splitContainer1 = new SplitContainer();
            progressBar = new CustomProgressBar();
            lblProgress = new Label();
            btn_Dwon = new Button();
            btn_Upload = new Button();
            label3 = new Label();
            label2 = new Label();
            label1 = new Label();
            circularProgressBar1 = new CircularProgressBar();
            ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
            splitContainer1.Panel1.SuspendLayout();
            splitContainer1.Panel2.SuspendLayout();
            splitContainer1.SuspendLayout();
            SuspendLayout();
            // 
            // splitContainer1
            // 
            splitContainer1.Dock = DockStyle.Fill;
            splitContainer1.Location = new Point(0, 0);
            splitContainer1.Margin = new Padding(4);
            splitContainer1.Name = "splitContainer1";
            splitContainer1.Orientation = Orientation.Horizontal;
            // 
            // splitContainer1.Panel1
            // 
            splitContainer1.Panel1.Controls.Add(progressBar);
            splitContainer1.Panel1.Controls.Add(lblProgress);
            // 
            // splitContainer1.Panel2
            // 
            splitContainer1.Panel2.Controls.Add(circularProgressBar1);
            splitContainer1.Panel2.Controls.Add(btn_Dwon);
            splitContainer1.Panel2.Controls.Add(btn_Upload);
            splitContainer1.Panel2.Controls.Add(label3);
            splitContainer1.Panel2.Controls.Add(label2);
            splitContainer1.Panel2.Controls.Add(label1);
            splitContainer1.Size = new Size(975, 135);
            splitContainer1.SplitterDistance = 47;
            splitContainer1.SplitterWidth = 6;
            splitContainer1.TabIndex = 0;
            // 
            // progressBar
            // 
            progressBar.Dock = DockStyle.Fill;
            progressBar.Location = new Point(0, 0);
            progressBar.Name = "progressBar";
            progressBar.RateText = "0 KB/s";
            progressBar.Size = new Size(975, 47);
            progressBar.TabIndex = 2;
            // 
            // lblProgress
            // 
            lblProgress.AutoSize = true;
            lblProgress.BackColor = Color.Transparent;
            lblProgress.Location = new Point(494, 16);
            lblProgress.Name = "lblProgress";
            lblProgress.Size = new Size(0, 21);
            lblProgress.TabIndex = 1;
            lblProgress.TextAlign = ContentAlignment.MiddleCenter;
            // 
            // btn_Dwon
            // 
            btn_Dwon.BackColor = Color.PeachPuff;
            btn_Dwon.Dock = DockStyle.Bottom;
            btn_Dwon.Location = new Point(385, 47);
            btn_Dwon.Name = "btn_Dwon";
            btn_Dwon.Size = new Size(205, 35);
            btn_Dwon.TabIndex = 4;
            btn_Dwon.Text = "下载(&D)";
            btn_Dwon.UseVisualStyleBackColor = false;
            btn_Dwon.Click += btn_Dwon_Click;
            // 
            // btn_Upload
            // 
            btn_Upload.BackColor = Color.PeachPuff;
            btn_Upload.Dock = DockStyle.Top;
            btn_Upload.FlatAppearance.BorderSize = 0;
            btn_Upload.FlatStyle = FlatStyle.Flat;
            btn_Upload.Location = new Point(385, 0);
            btn_Upload.Name = "btn_Upload";
            btn_Upload.Size = new Size(205, 32);
            btn_Upload.TabIndex = 3;
            btn_Upload.Text = "上传(&U)";
            btn_Upload.UseVisualStyleBackColor = false;
            btn_Upload.Click += btn_Upload_Click;
            // 
            // label3
            // 
            label3.Dock = DockStyle.Fill;
            label3.Location = new Point(385, 0);
            label3.Name = "label3";
            label3.Size = new Size(205, 82);
            label3.TabIndex = 2;
            label3.Text = "label3";
            // 
            // label2
            // 
            label2.Dock = DockStyle.Right;
            label2.Location = new Point(590, 0);
            label2.Name = "label2";
            label2.Size = new Size(385, 82);
            label2.TabIndex = 1;
            // 
            // label1
            // 
            label1.Dock = DockStyle.Left;
            label1.Location = new Point(0, 0);
            label1.Name = "label1";
            label1.Size = new Size(385, 82);
            label1.TabIndex = 0;
            // 
            // circularProgressBar1
            // 
            circularProgressBar1.Location = new Point(114, 15);
            circularProgressBar1.Maximum = 100;
            circularProgressBar1.Name = "circularProgressBar1";
            circularProgressBar1.Progress = 0;
            circularProgressBar1.Size = new Size(57, 55);
            circularProgressBar1.TabIndex = 5;
            // 
            // MainWinFrm
            // 
            AutoScaleDimensions = new SizeF(10F, 21F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(975, 135);
            Controls.Add(splitContainer1);
            Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
            Margin = new Padding(4);
            Name = "MainWinFrm";
            StartPosition = FormStartPosition.CenterScreen;
            Text = "Form1";
            splitContainer1.Panel1.ResumeLayout(false);
            splitContainer1.Panel1.PerformLayout();
            splitContainer1.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit();
            splitContainer1.ResumeLayout(false);
            ResumeLayout(false);
        }

        #endregion

        private SplitContainer splitContainer1;
        private Label label1;
        private Button btn_Dwon;
        private Button btn_Upload;
        private Label label3;
        private Label label2;
        private Label lblProgress;
        private CustomProgressBar progressBar;
        private CircularProgressBar circularProgressBar1;
    }
}

服务端:

FilesController.cs

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.IO;
using System.Threading.Tasks;

namespace LargeFileHandling.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class FilesController : ControllerBase
    {
        private readonly string _uploadFolderPath;

        public FilesController(FileStorageSettings fileStorageSettings)
        {
            _uploadFolderPath = fileStorageSettings.UploadFolderPath;

            // Ensure the upload folder exists
            if (!Directory.Exists(_uploadFolderPath))
            {
                Directory.CreateDirectory(_uploadFolderPath);
            }
        }

        // Upload large file
        [HttpPost("upload")]
        public async Task<IActionResult> UploadLargeFile(IFormFile file)
        {
            if (file == null || file.Length == 0)
            {
                return BadRequest(new { code = 400, message = "Upload failed. No file provided.", data = new { } });
            }

            var filename = Path.GetFileName(file.FileName);
            var filePath = Path.Combine(_uploadFolderPath, filename);

            await using (var stream = System.IO.File.Create(filePath))
            {
                await file.CopyToAsync(stream);
            }

            return Ok(new { code = 200, message = "File uploaded successfully.", data = new { filePath } });
        }

        // Check if file exists and return JSON response
        [HttpGet("exists/{fileName}")]
        public IActionResult CheckFileExists(string fileName)
        {
            var filePath = Path.Combine(_uploadFolderPath, fileName);
            if (System.IO.File.Exists(filePath))
            {
                return Ok(new { code = 200, message = "File exists.", data = new { filePath } });
            }
            else
            {
                return NotFound(new { code = 404, message = "File not found.", data = new { } });
            }
        }

        // Actual file download operation
        [HttpGet("download/{fileName}")]
        public IActionResult DownloadLargeFile(string fileName)
        {
            var filePath = Path.Combine(_uploadFolderPath, fileName);

            if (!System.IO.File.Exists(filePath))
            {
                return NotFound(new { code = 404, message = "File not found.", data = new { } });
            }

            var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            return new FileStreamResult(stream, "application/octet-stream")
            {
                FileDownloadName = fileName
            };
        }

        // Modified method to list downloadable files including files in subdirectories
        [HttpGet("list")]
        public IActionResult ListDownloadableFiles()
        {
            if (!Directory.Exists(_uploadFolderPath))
            {
                return NotFound(new { code = 404, message = "Upload folder not found.", data = new { } });
            }

            var files = Directory.GetFiles(_uploadFolderPath, "*.*", SearchOption.AllDirectories)
                                 .Select(file => file.Replace(_uploadFolderPath, "").TrimStart(Path.DirectorySeparatorChar))
                                 .ToList();

            return Ok(new { code = 200, message = "File list retrieved successfully.", data = new { files } });
        }
    }
}

appsettings.json

{
  "FileStorageSettings": {
    "UploadFolderPath": "F:\\Down"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

FileStorageSettings.cs

namespace LargeFileHandling
{
    public class FileStorageSettings
    {
        public string UploadFolderPath { get; set; }
    }
}

Program.cs

using LargeFileHandling;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

// 配置 Kestrel 服务器以允许大文件上传
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.Limits.MaxRequestBodySize = 10L * 1024 * 1024 * 1024; // 10GB
});

// 配置 FormOptions
builder.Services.Configure<FormOptions>(options =>
{
    options.MultipartBodyLengthLimit = 10L * 1024 * 1024 * 1024; // 10GB
});

// 绑定文件存储配置并注册为单例服务
builder.Services.Configure<FileStorageSettings>(builder.Configuration.GetSection("FileStorageSettings"));
builder.Services.AddSingleton(resolver =>
    resolver.GetRequiredService<IOptions<FileStorageSettings>>().Value);

// 其他服务和配置...
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// 应用的其余配置...
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

WeatherForecast.cs

namespace LargeFileHandling
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }

        public int TemperatureC { get; set; }

        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

        public string? Summary { get; set; }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/384721.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Days 29 ElfBoard LCD屏双电荷泵电路原理

7寸LCD屏幕的屏幕排线中采用的供电电压是5V供电&#xff0c;但是在屏幕工作时需要VCOM-5.3V、AVDD-12.5V、VGL--7V、VGH-17V几组电压&#xff0c;所以要对初始的5V电源进行DC-DC电压变换&#xff0c;在这里我们用到了双电荷泵电路。 再此电路中VCC_5V为电源输入&#xff0c;E…

2024年2月5日-2月11日周报

论文阅读 1. 本周计划2. 完成情况2.1 论文摘要2.2 网络结构2.3 损失函数2.4 优化器2.5 代码2.5.1 代码结果2.5.2 代码大致流程 4. 总结及收获4. 下周计划 1. 本周计划 阅读论文《Data-Driven Seismic Waveform Inversion: A Study on the Robustness and Generalization》并实…

嵌入式Qt 第一个Qt项目

一.创建Qt项目 打开Qt Creator 界面选择 New Project或者选择菜单栏 【文件】-【新建文件或项目】菜单项 弹出New Project对话框&#xff0c;选择Qt Widgets Application 选择【Choose】按钮&#xff0c;弹出如下对话框 设置项目名称和路径&#xff0c;按照向导进行下一步 选…

vue3中Pinia

一、pinia的简单使用 vuex和pinia的区别 参考网址&#xff1a;[Vuex] Vuex 5 by kiaking Pull Request #271 vuejs/rfcs GitHub 1.pinia没有mutations&#xff0c;只有&#xff1a;state、getters、actions 2.pinia分模块不需要models&#xff08;之前vuex分模块需要models…

肿瘤微环境异质性对治疗反应的影响(综述)

Influence of tumour micro-environment heterogeneity on therapeutic response | Nature 肿瘤的形成涉及肿瘤细胞与细胞外基质、肿瘤血管和免疫细胞的共同进化。肿瘤的成功生长和最终转移并不完全取决于肿瘤细胞的基因改变&#xff0c;还取决于这种突变在特定环境中带来的适…

【Java程序设计】【C00270】基于Springboot的moba类游戏攻略分享平台(有论文)

基于Springboot的moba类游戏攻略分享平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的游戏攻略分享平台 本系统分为系统功能模块、管理员功能模块、以及用户后台功能模块。 系统功能模块&#xff1a;在平台首…

算法-3-基本的数据结构

单双链表 1.单链表双链表如何反转 import java.util.ArrayList; import java.util.List;public class Code01_ReverseList {public static class Node {public int value;public Node next;public Node(int data) {value data;}}public static class DoubleNode {public int…

ZigBee学习——BDB

✨本博客参考了善学坊的教程&#xff0c;并总结了在实现过程中遇到的问题。 善学坊官网 文章目录 一、BDB简介二、BDB Commissioning Modes2.1 Network Steering2.2 Network Formation2.3 Finding and Binding&#xff08;F & B&#xff09;2.4 Touchlink 三、BDB Commissi…

图像处理之《黑盒扰动的可逆噪声流鲁棒水印》论文阅读

一、文章摘要 近年来&#xff0c;基于深度学习的数字水印框架得到了广泛的研究。现有的方法大多采用基于“编码器-噪声层-解码器”的架构&#xff0c;其中嵌入和提取过程分别由编码器和解码器完成。然而&#xff0c;这种框架的一个潜在缺点是编码器和解码器可能不能很好地耦合…

linux系统下vscode portable版本的python环境搭建003:venv

这里写自定义目录标题 python安装方案一. 使用源码安装&#xff08;有[构建工具](https://blog.csdn.net/ResumeProject/article/details/136095629)的情况下&#xff09;方案二.使用系统包管理器 虚拟环境安装TESTCG 本文目的&#xff1a;希望在获得一个新的系统之后&#xff…

电路设计(15)——篮球赛24秒违例倒计时报警器的proteus仿真

1.设计要求 设计、制作一个篮球赛24秒违例倒计时报警器。要求&#xff1a; &#xff08;1&#xff09;具有倒计时功能。可完整实现从“24”秒开始依序倒计时并显示倒计时过程&#xff0c;显示时间间隔为1秒。 &#xff08;2&#xff09;具有消隐功能。当“24”秒倒计时…

洛谷: P1308 [NOIP2011 普及组] 统计单词数

前言: 这道题没理解清题目表达意思&#xff0c;我开始想的是用map来记录个数&#xff0c;然后一个变量记录一开始出现的单词位置&#xff0c;不挺简单的吗&#xff0c;然后....就AC了2个..从错误提示能看到个数没啥问题&#xff0c;但是第一个单词位置不对&#xff0c;看了新样…

【C语言】assert断言:保护程序的利器

在软件开发过程中&#xff0c;我们经常会遇到一些假设条件或者预期行为。例如&#xff0c;我们可能假设一个函数的输入参数必须在某个范围内&#xff0c;或者某个变量的值应该满足特定的条件。当这些假设或预期行为被打破时&#xff0c;程序可能会出现异常行为&#xff0c;甚至…

GEE:随机森林回归教程(样本点、特征添加、训练、精度、参数优化)

作者:CSDN @ _养乐多_ 对于分类问题,这个输出通常是一个类别标签 ,而对于回归问题,输出通常是一个连续的数值。回归可以应用于多种场景,包括预测土壤PH值、土壤有机碳、土壤水分、碳密度、生物量、气温、海冰厚度、不透水面积百分比、植被覆盖度等。 本文将介绍在Google…

嵌入式Qt Qt 中的坐标系统

一.Qt中的坐标系统 实验1&#xff1a;窗口坐标大小 #include <QtGui/QApplication> #include <QPushButton> #include <QDebug> #include "widget.h" int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();qDebug()&…

Vue中v-on 可以监听多个方法吗

当然可以&#xff01;Vue.js是一款非常强大的JavaScript库&#xff0c;它提供了很多方便的方法和指令&#xff0c;使我们可以更容易地构建交互式的Web应用程序。其中&#xff0c;v-on指令是Vue.js中一个非常重要也非常常用的指令&#xff0c;它用于监听DOM事件&#xff0c;并在…

【DDD】学习笔记-四色建模法

或许正是认识到彩色 UML 在建模过程的不足之处&#xff0c;ThoughtWorks 的徐昊才在彩色 UML 基础之上提出了自己的“四色建模法”。可考的四色建模法资料仅见于徐昊在 InfoQ 上发表的文章运用四色建模法进行领域分析。在这篇文章中&#xff0c;徐昊回答了建模活动的一个关键问…

网络渗透测试:Wireshark抓取qq图片

Wireshark Wireshark Downloadhttps://www.wireshark.org/download.html 简介 WireShark是非常流行的网络封包分析工具&#xff0c;可以截取各种网络数据包&#xff0c;并显示数据包详细信息。常用于开发测试过程中各种问题定位。本文主要内容包括&#xff1a; 1、Wireshar…

docker安装、运行

1、安装 之前有docker的话&#xff0c;需要先卸载旧版本&#xff1a; sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 安装之前需要安装yum工具&#xff1a; sud…

Netty Review - ServerBootstrap源码解析

文章目录 概述源码分析小结 概述 ServerBootstrap bootstrap new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChannelInitializer<SocketChannel>() …