从异步方法填充数据绑定属性的最佳方法是什么?

时间:2019-02-12 15:24:40

标签: c# asp.net-mvc entity-framework asynchronous async-await

我有一个简单的要求要达到。基本上,我有一个包含企业列表的视图。业务列表的属性包含在我的viewmodel类中,该类又绑定到该视图。这是带有业务列表的简单MVC应用程序。

但是,我遇到的问题是,我派生了另一个类的业务列表,该类依赖于视图模型,并且该类基本上类似于我称为BusinessService的存储库。繁忙的服务由异步方法组成,这是我的难题,当从viewModel的Ctor或属性的getter进行调用时,我的应用程序挂起。该呼叫也是在业务服务内非常规的EF数据库,因此不确定哪种正确方法是正确的。请参见下面的代码:

ViewModel:

    #region Ctor

    public BusinessListViewModel(IBusinessService businessService, IStringBuilder builder)
    {
        _businessService = businessService;
        _builder = builder;

        InitBusinesses().Wait(); //OPTION 1
    }

    #endregion

    #region Properties

    public IEnumerable<BusinessViewModel> _businesses;
    public IEnumerable<BusinessViewModel> Businesses
    {
        get
        {
            if (_businesses == null)
            {
                InitBusinesses().Wait(); //OPTION 2
            }
            return _businesses;
        }
        set => _businesses = value;
    }

    private async Task InitBusinesses()
    {
        var response = await _businessService.Get();
        Businesses = response.IsSuccessful 
                            ? response.Data.Select(p => new BusinessViewModel(_builder, p)) 
                            : new List<BusinessViewModel>();
    }

业务服务:

    #region Service Methods

    public async Task<Response<IEnumerable<Models.Business>>> Get()
    {
        var data = await Db.Businesses.ToListAsync();
        return new Response<IEnumerable<Models.Business>>
        {
            IsSuccessful = true,
            Message = "Successful",
            Data = Mapper.Map<List<Models.Business>>(data)
        };
    }

请您告知最佳模式和正确方法,我已经知道这是错误的>谢谢

2 个答案:

答案 0 :(得分:1)

我写了article on the subject

当UI框架要求您的代码显示某些内容时,必须立即(同步)显示它。 ViewModel构造函数和数据绑定属性应该是同步的和立即的。根本不可以进行网络I / O。即使您可以正常工作(可能),所有要做的就是阻止UI线程,从而降低用户体验。

一个更合适的解决方案是同步初始化进入加载状态(“ Loading ...”消息,微调框等),并启动异步操作。然后,当操作完成时,使用实际数据更新 UI。

答案 1 :(得分:0)

您应该考虑使用返回Task的工厂方法

private BusinessListViewModel(IBusinessService businessService, IStringBuilder builder)
{
    _businessService = businessService;
    _builder = builder;
}

public static async Task<BusinessListViewModel> Create(IBusinessService businessService, IStringBuilder builder)
{
    var instance = new BusinessListViewModel(businessService, builder)
    await InitBusiness();
    return instance;
}