温馨提示:本文翻译自stackoverflow.com,查看原文请点击:c# - Net Core 3.1 Return a Task with a result that includes details of the exception?
ado.net asp.net-core-3.1 async-await c# task

c# - Net Core 3.1返回一个任务,其结果包括异常的详细信息?

发布于 2020-04-16 10:13:32

我正在使用ADO.Net填充数据表,该数据表填充方法已放入单独的存储库中。我将存储库/接口注入到测试页面模型中。页面模型方法“ OnPostUpdateAlarmDataTableAsync”需要调用接口并请求填充数据表。我想从填充此表的任务中返回结果,因此,如果任务由于某种原因而失败,那么我可以在UI上通知用户,我也想从页面模型中记录错误的详细信息,因为是调用线程。

当前的编译错误说“无法为隐式类型的变量分配void”,但是我尝试更改代码中的任何组合,但都无法正确编译。我想实现能够从异步操作中返回任务的相关信息,其中包含有关异常的详细信息。

接口:

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?
        }
    }
}

PageModel:

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);
    }
}

查看更多

提问者
OJB1
被浏览
183
Nkosi 2020-02-04 10:36

原始示例中的注释显示了您应该实际执行的操作。

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

就像是

/// <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);
    }
}