You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于.NET 7的MAUI项目点位与照片存储优化问题咨询

问题解决方案

1. 避免UI阻塞的大对象存储方案

客户端侧

  • 异步分离UI与业务逻辑:所有耗时操作(对象克隆、数据上传)必须通过await异步执行,禁止使用.Result或.Wait()阻塞UI线程。若有本地数据预处理(如照片压缩、点位格式化),可通过Task.Run将逻辑放到后台线程,再通过MainThread.BeginInvokeOnMainThread更新UI:
    // 后台处理数据,不占用UI线程
    var processedData = await Task.Run(() => {
        var cloned = BigObject.Clone();
        cloned.Points.Clear();
        cloned.Photos.Clear();
        return cloned;
    });
    // 异步上传,UI保持响应
    var simpleObj = await saveJustAsync(processedData);
    
  • 分批次上传:将点位、照片拆分为小批次(如20个点位/10张照片为一批),完成一批后再执行下一批,降低单次请求负载。

服务端侧

  • EF批量操作优化:存储点位时用DbContext.AddRange()替代循环Add(),减少EF跟踪开销;配合EF批量扩展包(如EFCore.BulkExtensions)提升提交效率:
    await _context.Points.AddRangeAsync(simpleObject.Points);
    await _context.BulkSaveChangesAsync(); // 批量提交减少数据库交互次数
    
  • Azure Blob分块上传:针对大照片,使用分块上传API拆分文件为4MB-100MB的块并行上传,避免超时或资源占用过高:
    var blobClient = _blobServiceClient.GetBlobContainerClient("photos").GetBlobClient(photoFileName);
    await blobClient.UploadAsync(photoStream, new BlobUploadOptions {
        TransferOptions = new StorageTransferOptions {
            MaximumConcurrency = 4, // 控制并发数,避免资源耗尽
            InitialTransferSize = 4 * 1024 * 1024 // 初始块大小设为4MB
        }
    });
    

2. 获取存储实时状态的方案

客户端侧

  • 用IProgress<T>传递进度:定义进度模型,在上传过程中实时通知UI更新:
    // 进度模型
    public class UploadProgress
    {
        public int TotalItems { get; set; }
        public int CompletedItems { get; set; }
        public string CurrentStatus { get; set; }
    }
    
    // 客户端调用时传入进度回调
    var progress = new Progress<UploadProgress>(update => {
        // 在UI线程更新进度条、状态文本
        ProgressBar.Value = (double)update.CompletedItems / update.TotalItems * 100;
        StatusLabel.Text = update.CurrentStatus;
    });
    
    await savePointsAsync(simpleObject, progress);
    
  • 上传方法内更新进度:
    public async Task savePointsAsync(SimpleObject obj, IProgress<UploadProgress> progress)
    {
        var total = obj.Points.Count;
        var completed = 0;
        foreach (var point in obj.Points)
        {
            await _pointService.SaveAsync(point);
            completed++;
            progress.Report(new UploadProgress {
                TotalItems = total,
                CompletedItems = completed,
                CurrentStatus = $"上传点位 {completed}/{total}"
            });
        }
    }
    

服务端侧

  • 建立任务状态表:创建UploadTask实体记录每个上传任务的进度与状态:
    public class UploadTask
    {
        public Guid Id { get; set; }
        public string UserId { get; set; }
        public int TotalPoints { get; set; }
        public int CompletedPoints { get; set; }
        public int TotalPhotos { get; set; }
        public int CompletedPhotos { get; set; }
        public UploadStatus Status { get; set; } // 待处理/处理中/完成/失败
        public DateTime CreatedTime { get; set; }
    }
    
    public enum UploadStatus
    {
        Pending,
        Processing,
        Completed,
        Failed
    }
    
  • 实时更新与状态查询接口:处理任务时实时更新UploadTask,并提供API供客户端查询:
    // 更新进度
    public async Task UpdateTaskProgress(Guid taskId, int completedPoints)
    {
        var task = await _context.UploadTasks.FindAsync(taskId);
        task.CompletedPoints = completedPoints;
        task.Status = UploadStatus.Processing;
        await _context.SaveChangesAsync();
    }
    
    // 查询状态接口
    [HttpGet("tasks/{taskId}")]
    public async Task<IActionResult> GetTaskStatus(Guid taskId)
    {
        var task = await _context.UploadTasks.FindAsync(taskId);
        return Ok(task);
    }
    
  • 可选:SignalR实时推送:通过SignalR建立长连接,服务端主动推送进度变化,替代客户端轮询,提升实时性。

3. 多用户存储的队列机制实现

服务端侧

  • Azure Queue Storage实现任务队列:
    1. 客户端提交请求时,服务端先创建UploadTask并返回taskId,再将任务信息序列化放入队列:
      var queueClient = _queueServiceClient.GetQueueClient("upload-tasks");
      await queueClient.CreateIfNotExistsAsync();
      var message = JsonSerializer.Serialize(new { TaskId = task.Id, ObjectId = simpleObj.Id });
      await queueClient.SendMessageAsync(message);
      
    2. 后台Worker监听队列,取出任务后异步处理存储逻辑:
      while (true)
      {
          var response = await queueClient.ReceiveMessageAsync();
          if (response.Value == null)
          {
              await Task.Delay(1000);
              continue;
          }
          try
          {
              var taskData = JsonSerializer.Deserialize<TaskMessage>(response.Value.Body.ToString());
              // 执行点位、照片存储,同时更新UploadTask状态
              await ProcessUploadTask(taskData.TaskId);
              await queueClient.DeleteMessageAsync(response.Value.MessageId, response.Value.PopReceipt);
          }
          catch (Exception ex)
          {
              // 异常处理:限制重试次数后重新入队
              await queueClient.UpdateMessageAsync(response.Value.MessageId, response.Value.PopReceipt, TimeSpan.FromMinutes(5));
          }
      }
      
  • 并发控制与限流:在Worker中用SemaphoreSlim限制同时处理的任务数;针对用户设置并发上限(如每个用户最多同时处理2个上传任务),避免资源耗尽。
  • 乐观锁避免冲突:在UploadTask中添加Timestamp字段,EF自动用其实现乐观锁,防止多线程同时修改同一任务状态:
    public byte[] Timestamp { get; set; }
    
    DbContext配置:
    modelBuilder.Entity<UploadTask>().Property(t => t.Timestamp).IsRowVersion();
    

内容的提问来源于stack exchange,提问作者Mafyou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 21:15:04