Blazor服务端复用数据访问接口实现文件导入数据库的问题
Hey there! Let's sort out that null reference exception you're hitting with IPermitData in your TextFileParser class. The core issue is that you're declaring IPermitData _db; but never assigning a valid instance to it—luckily, since you're already using dependency injection (DI) in your Blazor Server app, we can reuse that system to get the instance we need.
Step 1: Update TextFileParser to Use Constructor Injection
Instead of declaring _db inside the method, we'll inject it directly through the class constructor. This lets the DI container automatically pass in the registered IPermitData instance when creating a TextFileParser. We'll also fix the async handling since InsertPermit is an asynchronous method.
Here's the revised TextFileParser code:
public class TextFileParser { private readonly IPermitData _db; // Inject IPermitData via constructor public TextFileParser(IPermitData db) { _db = db; } // Change to async Task instead of void for proper async handling public async Task InsertTextFileData(string filePath) { string errMessage = string.Empty; FileInfo file = new FileInfo(filePath); if (!File.Exists(file.FullName)) { errMessage = "File not found!"; // Consider logging this error instead of just storing it return; } if (file.Length == 0) // Fixed your condition here (>=0 will always be true) { errMessage = "File has no data!"; return; } string delimiter = "\t"; using StreamReader fileReader = new StreamReader(filePath); int header = 1; while (!fileReader.EndOfStream) { string vText = fileReader.ReadLine(); if (string.IsNullOrEmpty(vText)) continue; // Skip empty lines if (header == 1) { header++; // Optional: Validate header columns here if needed continue; } string[] vString = vText.Split(delimiter, StringSplitOptions.None); // Create a new PermitModel for each record to avoid reference issues PermitModel permitRecord = new PermitModel(); // Map your columns (same as before) permitRecord.PD_ParcelID = vString[0]; permitRecord.PD_Situs1 = vString[1]; permitRecord.PD_Owner = vString[2]; permitRecord.PD_Addr1 = vString[3]; permitRecord.PD_Addr2 = vString[4]; permitRecord.ADDR_3 = vString[5]; permitRecord.PD_City = vString[6]; permitRecord.PD_State = vString[7]; permitRecord.PD_Zip = vString[8]; permitRecord.Type_Construction = vString[9]; permitRecord.Estimated_Cost = vString[10]; permitRecord.Permit_Issue_Date = vString[11]; permitRecord.Permit_Type = vString[12]; permitRecord.Property_Type = vString[13]; permitRecord.Permit_NO = vString[14]; permitRecord.Completion_Date = vString[15]; permitRecord.Percent_Complete = vString[16]; permitRecord.Modified_Date = vString[17]; permitRecord.Note = vString[18]; permitRecord.Note_Date = vString[19]; permitRecord.Submission_Date = vString[20]; permitRecord.Submitter = vString[21]; permitRecord.Submitter_Phone = vString[22]; permitRecord.Submitter_Email = vString[23]; permitRecord.Land_AV = vString[24]; permitRecord.Impr_AV = vString[25]; permitRecord.Sec_Location = vString[26]; try { await _db.InsertPermit(permitRecord); // Use await for async method } catch (Exception ex) { // Log the exception instead of just continuing—helps with debugging // Example: Logger.LogError(ex, "Failed to insert permit record {ParcelId}", permitRecord.PD_ParcelID); continue; } } } }
Key fixes here:
- Constructor injection for
IPermitDataensures_dbis always a valid instance - Changed
InsertTextFileDatatoasync Taskto properly handle the asynchronousInsertPermitmethod - Fixed the file length check (original
>=0would never trigger the "no data" message) - Created a new
PermitModelper record to avoid accidental overwriting of data - Added a check for empty lines to prevent index errors
Step 2: Register TextFileParser with the DI Container
Now that TextFileParser has a dependency on IPermitData, you need to register it in your Startup.cs (or Program.cs if using .NET 6+) so the DI container can resolve its dependencies.
Add this line to your ConfigureServices method:
// Use the same lifetime as your IPermitData registration (likely Scoped) services.AddScoped<TextFileParser>();
Step 3: Inject and Use TextFileParser in Your Razor Page
Instead of injecting IPermitData directly if you're using the parser, inject TextFileParser and call its method:
@inject TextFileParser textFileParser <!-- Your UI here, e.g., a file input or button to trigger processing --> <button @onclick="ProcessSampleFile">Process File</button> @code { private async Task ProcessSampleFile() { string filePath = "path/to/your/file.txt"; // Replace with actual path await textFileParser.InsertTextFileData(filePath); // Add success feedback here if needed } }
Extra Notes
- Async Best Practices: Avoid using
voidfor async methods (except event handlers) because it can lead to unobserved exceptions. Usingasync Taskensures exceptions can be caught properly. - Error Logging: Add a logger (inject
ILogger<TextFileParser>via constructor) to log failed inserts—this will save you a lot of time debugging issues with bad data. - File Path Handling: In Blazor Server, be careful with file paths—ensure the app has permission to read the file, and consider using a file upload component to let users select files instead of hardcoding paths.
内容的提问来源于stack exchange,提问作者Jason Garner

