0

我有一个庞大的数据集来支撑我的 UI,所以我想我会创建一个后台调用来填充我的本地存储库并立即在 UI 中显示我的其他控件,并在我得到响应时加载异步调用的结果。

我找到了一个有用的教程,但我仍然必须等到所有结果都加载完毕才能看到任何控件。

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

代码更新

我创建了一个名为 Services 的文件夹并在该文件夹中创建了 FacilitiesService.cs,见下文:

public class FacilitiesService
{
    internal async Task<List<Facility>> GetFacilitiesBySourceDbAsync(string sourceDb)
    {
        var fac = new Facility();

        var con = Connect(); // Omitted

        try
        {
            con.Open();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: GetFacilityBySourceDb " + ex.Message);
        }

        try
        {
            OracleDataReader reader = null;
            // Requestor
            var cmd = new OracleCommand("SELECT FACILITY, FACILITY_ID FROM MyTable where (source_db = '" + sourceDb + "')", con);

            reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                fac.Add(new Facility()
                {
                    FacilityName = reader["FACILITY"].ToString(),
                    FacilityId = reader["FACILITY_ID"].ToString()
                });
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            con.Close();
            con.Dispose();
        }

        return fac;
    }
}

然后在我的 HomeController.cs 我有以下内容:

public class HomeController
{
    public async Task<List<Facility>> FacilitiesAsync()
    {
        ViewBag.SyncOrAsync = "Asynchronous";
        var service = new FacilitiesService();

        this._facilities = new List<Facility>();

        var facilities = await service.GetFacilitiesBySourceDbAsync("TEST");

        foreach (var item in facilities)
        {
            Facility fac = new Facility()
            {
                FacilityName = item.FacilityName,
                FacilityId = item.FacilityId
            };

            _facilities.Add(fac);
        }

        return _facilities;
    }
}

这是我的设施(模型)类:

public class Facility : List<Facility>
{
    [Required]
    [Display(Name = "Facility")]
    public string FacilityName { get; set; }
    public string FacilityId { get; set; }

    public Facility()
    {
        // Default Constructor
    }

    public Facility(string facilityName, string facilityId)
    {
        this.FacilityName = facilityName;
        this.FacilityId = facilityId;
    }
}

我正在使用 Ajax 调用从 About.cshtml 页面中的函数调用启动代码中的设施Async 方法,当用户使用“标签”的 id 关闭 tetbox/输入控件时,我可以将其切换为某些东西稍后,但是当我逐步执行代码隐藏时,我得到了数据,我看到 beforeSend 和 complete 函数都会触发警报:

<script type="text/javascript">
$(function () {
    var availableTags = [
    // Neeed data from function call to populate this list
    ];
    $("#tags").autocomplete({
        source: availableTags
    });
    $("#tags").focusout(function () {
        var result = null;
        $.ajax({
            beforeSend: function() {
                alert("Testing");
            },
            url: "FacilitiesAsync",
            success: function(data) {
                result = data;
            },
            complete: function () {
                alert(result);
            }
        });
    });
});
</script>

@using (Html.BeginForm()) {
     <div class="ui-widget">
        <label for="tags">Tags: </label>
        <input id="tags" />
     </div>
}

这很好用!但是,我想从对代码隐藏的调用中获取数据来填充数组 availableTags,但我不知道该怎么做。建议?

4

1 回答 1

0

实现有一些问题,方法有一个问题。

首先,GetFacilitiesBySourceDbAsync不包含await. 编译器会在这种情况下发出警告,通知您这样做时它并不是真正的异步方法;它将同步运行。这是一个重要的警告。如果你想要异步代码,你需要让它一直异步。这意味着使用异步数据库方法(ExecuteReaderAsync等)。

其次,Task.WhenAll调用Index是没有意义的(因为你只传递了一个任务)。此外,由于Index是同步的但调用了异步方法,因此未显示的代码可能是调用Result,这在 ASP.NET 上是禁止的。正如我在博客中解释的那样,一旦你的代码实际上是异步的,这实际上会死锁。async

但即使你修复了这些,它也不会做你想做的事。这种方法有一个问题,那就是它async不会改变 HTTP 协议(​​这也是我博客的链接)。asyncASP.NET MVC 理解异步方法,并且在操作方法完成之前不会完成请求。您需要使用 AJAX 之类的东西来让网页执行您想要的操作。

于 2013-11-14T10:47:49.600 回答