Net Core 3.1 Return 任务的结果包含异常的详细信息?

Net Core 3.1 Return a Task with a result that includes details of the exception?

我正在使用ADO.Net填充数据table,数据table填充方法我已放入单独的存储库中。我将 repository/interface 注入到测试页面模型中。页面模型方法"OnPostUpdateAlarmDataTableAsync"需要调用接口请求填充数据table。我想 return 填充这个 table 的任务的结果,所以如果任务由于任何原因失败,我可以在 UI 上通知用户,我也想记录页面模型错误的详细信息,因为这是调用线程。

当前编译错误显示 "cannot assign void to an implicitly-typed variable" 但是我尝试更改代码中的任何组合,但始终无法正确编译。能够 return 来自异步操作的任务以及包含异常详细信息的相关信息是我想要实现的目标。

接口:

public interface IAdoNetRepository
{
    Task FillAlarmsDataTable();
}

存储库:

public class AdoNetRepository : IAdoNetRepository
{
    public readonly IConfiguration _config;

    public AdoNetRepository(IConfiguration config)
    {
        _config = config;
    }

    // Used for method below GetUserGroupsData()
    public static SqlDataAdapter dataAdapter = new SqlDataAdapter();
    public static DataTable alarmDataTable;


    public async Task FillAlarmsDataTable()
    {
        string connectionString = _config.GetConnectionString("Data:DefaultConnection:ConnectionString");

        try
        {
            SqlConnection connection = new SqlConnection(connectionString);
            string cmdText1 = "SELECT * FROM [dbo].[Alarms] ORDER BY Name";

            // Create a new data adapter based on the specified query.
            dataAdapter = new SqlDataAdapter(cmdText1, connection);

            // Populate a new data table and bind it to the BindingSource.
            alarmDataTable = new DataTable
            {
                Locale = CultureInfo.InvariantCulture
            };
            await Task.Run(() => dataAdapter.Fill(alarmDataTable));
            //dataAdapter.Fill(alarmDataTable);

            return; // Return what ?
        }
        catch (Exception ex)
        {
            // Return the task with details of the exception
            return; // Return what?
        }
    }
}

页面模型:

public class TestModel : PageModel
{

    private readonly IAdoNetRepository _adoNetRepository;

    public TestModel(IAdoNetRepository adoNetRepository)
    {
        _adoNetRepository = adoNetRepository;
    }

    public async Task<IActionResult> OnPostUpdateAlarmDataTableAsync()
    {
        // This gets squiggly line compile error            
        var result = await _adoNetRepository.FillAlarmsDataTable();

        if (!result.Succeeded)
        {
            // log the exception returned from the task that failed!
        }

        return new JsonResult(result);
    }
}

原始示例中的注释显示了您实际应该做什么。

您需要创建一个模型来存储所需的信息。

类似

/// <summary>
/// Represents the result of an ADO.Net operation.
/// </summary>
public class AdoNetResult {
    private List<Exception> _errors = new List<Exception>();

    public bool Succeeded { get; protected set; }
    public IEnumerable<Exception> Errors => _errors;

    public static AdoNetResult Success { get; } = new AdoNetResult { Succeeded = true };
    public static AdoNetResult Failed(params Exception[] errors) {
        var result = new AdoNetResult { Succeeded = false };
        if (errors != null) {
            result._errors.AddRange(errors);
        }
        return result;
    }
}

但是界面需要重构

public interface IAdoNetRepository {
    Task<AdoNetResult> FillAlarmsDataTable();
}

和实施

public async Task<AdoNetResult> FillAlarmsDataTable() {
    string connectionString = _config.GetConnectionString("Data:DefaultConnection:ConnectionString");

    try {
        SqlConnection connection = new SqlConnection(connectionString);
        string cmdText1 = "SELECT * FROM [dbo].[Alarms] ORDER BY Name";

        // Create a new data adapter based on the specified query.
        dataAdapter = new SqlDataAdapter(cmdText1, connection);

        // Populate a new data table and bind it to the BindingSource.
        alarmDataTable = new DataTable {
            Locale = CultureInfo.InvariantCulture
        };
        await Task.Run(() => dataAdapter.Fill(alarmDataTable));

        // Return what ?
        return AdoNetResult.Success; 
    } catch (Exception ex) {
        // Return the task with details of the exception
        return AdoNetResult.Failed(ex);
    }
}

完成后,原始代码应该可以按预期工作

public async Task<IActionResult> OnPostUpdateAlarmDataTableAsync() {

    var result = await _adoNetRepository.FillAlarmsDataTable();

    if (!result.Succeeded) {
        // log the exception returned from the task that failed!
        //result.Errors
    }

    return new JsonResult(result);
}

另一种方法是让 FillAlarmsDataTable 抛出它可能遇到的任何异常

public Task FillAlarmsDataTable() {
    string connectionString = _config.GetConnectionString("Data:DefaultConnection:ConnectionString");

    SqlConnection connection = new SqlConnection(connectionString);
    string cmdText1 = "SELECT * FROM [dbo].[Alarms] ORDER BY Name";

    // Create a new data adapter based on the specified query.
    dataAdapter = new SqlDataAdapter(cmdText1, connection);

    // Populate a new data table and bind it to the BindingSource.
    alarmDataTable = new DataTable {
        Locale = CultureInfo.InvariantCulture
    };
    return Task.Run(() => dataAdapter.Fill(alarmDataTable));
}

捕获(捕获)正在使用的异常并做出相应响应

public async Task<IActionResult> OnPostUpdateAlarmDataTableAsync() {
    try {
        await _adoNetRepository.FillAlarmsDataTable();
        return Ok(); //200 OK
    catch(Exception ex) {
        //...log the exception returned from the task that failed!

        return new ExceptionResult(ex, includeErrorDetail:true);
    }
}