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

如何将Angular上传的CSV文件发送至.NET Web服务并入库?

Great question! Let's break this down step by step—your core workflow idea is solid, but we can simplify it and fill in the missing pieces to get a working end-to-end solution.

First: Is Your Initial Workflow Correct?

Your high-level flow (Upload → Parse → Save to DB) is right, but you don't need a separate "Web Service" layer here. .NET Web API can handle both receiving the uploaded file and parsing it directly, then persisting to the database. Your existing .NET code is written to read a local file, which won't work for HTTP file uploads—that's a key gap we'll fix.

Key Gaps You're Missing

  1. Angular code to send the uploaded file to the API via HTTP (using FormData)
  2. A .NET Web API controller endpoint to accept the uploaded file stream
  3. Database persistence logic (using EF Core, for example)
  4. Error handling for file validation, CSV parsing failures, and database errors
  5. Proper handling of edge cases like malformed CSV rows (e.g., fields with commas inside quotes)

Full End-to-End Implementation

1. Angular Frontend

Updated HTML (fixed click binding and added validation)

<input type="file" accept=".csv" (change)="onFileSelected($event)" />
<button type="submit" (click)="onUpload()" class="button" [disabled]="!selectedFile">Upload</button>

TypeScript Component

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-csv-upload',
  templateUrl: './csv-upload.component.html'
})
export class CsvUploadComponent {
  selectedFile: File | null = null;

  constructor(private http: HttpClient) {}

  onFileSelected(event: Event): void {
    const input = event.target as HTMLInputElement;
    if (input.files?.length) {
      this.selectedFile = input.files[0];
      // Quick file type check
      if (!this.selectedFile.name.endsWith('.csv')) {
        alert('Please select a valid CSV file!');
        this.selectedFile = null;
      }
    }
  }

  onUpload(): void {
    if (!this.selectedFile) return;

    const formData = new FormData();
    formData.append('csvFile', this.selectedFile);

    // Replace with your actual API URL
    this.http.post('https://your-api-domain/api/csv/upload', formData)
      .subscribe({
        next: () => {
          alert('Upload successful! Data saved to database.');
          this.selectedFile = null;
        },
        error: (err) => {
          console.error('Upload failed:', err);
          alert('Oops, something went wrong. Check the console for details.');
        }
      });
  }
}

2. .NET Web API Backend

First, install required NuGet packages:

Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package CsvHelper # Optional but highly recommended for robust CSV parsing

Step 1: Define Entity and DbContext

// MonitoredEvent.cs
public class MonitoredEvent
{
    public int Id { get; set; } // Primary key
    public string Venue { get; set; } = string.Empty;
    public string Event { get; set; } = string.Empty;
    public string Section { get; set; } = string.Empty;
    public DateTime EventDate { get; set; }
    public TimeSpan Time { get; set; }
    public float TotalOrder { get; set; }
    public float TLC { get; set; }
    public string TicketType { get; set; } = string.Empty;
    public string Source { get; set; } = string.Empty;
    public string TicketPage { get; set; } = string.Empty;
}

// AppDbContext.cs
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<MonitoredEvent> MonitoredEvents { get; set; }
}

Step 2: Create CSV Upload Controller

We'll cover two parsing options—your manual split approach, and a more robust one with CsvHelper.

Option 1: Manual Parsing (Based on Your Existing Code)
// CsvUploadController.cs
[ApiController]
[Route("api/csv")]
public class CsvUploadController : ControllerBase
{
    private readonly AppDbContext _dbContext;

    public CsvUploadController(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpPost("upload")]
    public async Task<IActionResult> UploadCsv(IFormFile csvFile)
    {
        // Validate input
        if (csvFile == null || csvFile.Length == 0)
            return BadRequest("No file was uploaded.");
        
        if (!Path.GetExtension(csvFile.FileName).Equals(".csv", StringComparison.OrdinalIgnoreCase))
            return BadRequest("Please upload a CSV file.");

        var events = new List<MonitoredEvent>();

        using (var reader = new StreamReader(csvFile.OpenReadStream()))
        {
            // Skip header row
            await reader.ReadLineAsync();

            string line;
            while ((line = await reader.ReadLineAsync()) != null)
            {
                var values = line.Split(',');
                // Note: This will break if any fields have commas inside quotes! Use CsvHelper for that.
                if (values.Length < 10) continue; // Skip malformed rows

                var evt = new MonitoredEvent
                {
                    Venue = values[0],
                    Event = values[1],
                    Section = values[2]
                };

                // Parse date/time/numbers with error handling
                if (DateTime.TryParse(values[3], out var eventDate))
                    evt.EventDate = eventDate.Date;
                
                if (TimeSpan.TryParse(values[4], out var eventTime))
                    evt.Time = eventTime;
                
                if (float.TryParse(values[5], out var totalOrder))
                    evt.TotalOrder = totalOrder;
                
                if (float.TryParse(values[6], out var tlc))
                    evt.TLC = tlc;

                evt.TicketType = values[7];
                evt.Source = values[8];
                evt.TicketPage = values[9];

                events.Add(evt);
            }
        }

        // Save to database
        await _dbContext.MonitoredEvents.AddRangeAsync(events);
        await _dbContext.SaveChangesAsync();

        return Ok(new { TotalRecords = events.Count, Message = "Data saved successfully." });
    }
}
Option 2: Robust Parsing with CsvHelper

This handles edge cases like quoted fields with commas:

using CsvHelper;
using System.Globalization;

[HttpPost("upload")]
public async Task<IActionResult> UploadCsv(IFormFile csvFile)
{
    if (csvFile == null || csvFile.Length == 0)
        return BadRequest("No file was uploaded.");
    
    if (!Path.GetExtension(csvFile.FileName).Equals(".csv", StringComparison.OrdinalIgnoreCase))
        return BadRequest("Please upload a CSV file.");

    List<MonitoredEvent> events;

    using (var reader = new StreamReader(csvFile.OpenReadStream()))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        // Map CSV headers to your entity properties (skip if headers match property names exactly)
        csv.Context.RegisterClassMap<MonitoredEventMap>();
        csv.Read();
        csv.ReadHeader();
        events = csv.GetRecords<MonitoredEvent>().ToList();
    }

    await _dbContext.MonitoredEvents.AddRangeAsync(events);
    await _dbContext.SaveChangesAsync();

    return Ok(new { TotalRecords = events.Count, Message = "Data saved successfully." });
}

// CSV mapping class (adjust if your CSV headers don't match property names)
public class MonitoredEventMap : ClassMap<MonitoredEvent>
{
    public MonitoredEventMap()
    {
        Map(m => m.Venue).Name("Venue");
        Map(m => m.Event).Name("Event");
        Map(m => m.Section).Name("Section");
        Map(m => m.EventDate).Name("EventDate");
        Map(m => m.Time).Name("Time");
        Map(m => m.TotalOrder).Name("TotalOrder");
        Map(m => m.TLC).Name("TLC");
        Map(m => m.TicketType).Name("TicketType");
        Map(m => m.Source).Name("Source");
        Map(m => m.TicketPage).Name("TicketPage");
    }
}

Step 3: Configure Database Connection

Add this to appsettings.json:

"ConnectionStrings": {
  "DefaultConnection": "Server=YOUR_SERVER_NAME;Database=YOUR_DB_NAME;Trusted_Connection=True;TrustServerCertificate=True;"
}

Register the DbContext in Program.cs:

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

3. Pro Tips for Production

  • Error Handling: Add global exception filters to catch and return friendly errors
  • File Size Limits: Configure max upload size in Program.cs:
    builder.Services.Configure<FormOptions>(options =>
    {
        options.MultipartBodyLengthLimit = 10 * 1024 * 1024; // 10MB limit
    });
    
  • Transactions: Wrap database operations in a transaction to ensure atomicity
  • Logging: Add a logging library (like Serilog) to track uploads, parsing, and errors

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:56:14