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

C# 从异步方法填充数据绑定属性的最佳方法是什么?,c#,asp.net-mvc,entity-framework,asynchronous,async-await,C#,Asp.net Mvc,Entity Framework,Asynchronous,Async Await,我有一个简单的要求,我正在努力实现。基本上,我有一个视图,其中包含一个企业列表。业务列表的属性体现在my viewmodel类中,该类又绑定到视图。这是一个简单的MVC应用程序,包含一个业务列表 然而,我遇到的问题是,我为另一个类派生了业务列表,该类依赖于视图模型,它基本上类似于我称之为BusinessService的存储库。繁忙服务由异步方法组成,这是我面临的难题,当调用来自viewModel的Ctor或属性的getter时,我的应用程序挂起。调用的是businessservice中的EF数据

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

然而,我遇到的问题是,我为另一个类派生了业务列表,该类依赖于视图模型,它基本上类似于我称之为BusinessService的存储库。繁忙服务由异步方法组成,这是我面临的难题,当调用来自viewModel的Ctor或属性的getter时,我的应用程序挂起。调用的是businessservice中的EF数据库asynchrounous,我不确定正确的方法是什么。请参阅下面的代码:

视图模型:

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

请您建议最好的模式和正确的方式来做这件事,我已经知道这是错误的。谢谢您

< p>您应该考虑使用一个返回任务

的工厂方法。 我写了一封信

当UI框架要求代码显示某些内容时,必须立即同步显示。ViewModel构造函数和数据绑定属性应该是同步的和即时的。进行网络I/O根本不是一种选择;即使你能让它正常工作,也只会阻塞你的UI线程,降低你的用户体验


一个更合适的解决方案是同步初始化到加载状态加载。。。消息、微调器等,并启动异步操作。然后,当操作完成时,用实际数据更新UI。

您询问的两个选项都不好。属性不应加载数据。方法应该加载数据。属性应该包含有关对象的信息,而不是从其他源加载数据的方法。在用于封装信息模型的数据与用于检索该信息数据的逻辑之间保持明显的分离layer@mason谢谢你的回复,如上所述,我已经明白这不是正确的方式。即使使用工作单元&存储库模式,根据您的解释,您将如何填充属性以绑定到用户界面?不要让视图模型来完成。让外面的代码去做。它通常看起来像var myViewModel=newmyviewmodel;myViewModel.Businesses=await\u repository.GetBusinessesAsync@梅森:正是在我出错的地方,我试图让我的控制器尽可能精简,但我认为这种方式最有意义。要么使用依赖注入,要么通过接口契约。根据你的例子,两者都使用不会产生任何效果sense@JohnWu:对不起,我没注意到这是ASP.NET。MVC不使用数据绑定;MVC实现这一点的方法是让控制器异步加载所有数据,然后在ViewModel上设置属性。在MVC中,ViewModels不应该加载自己的数据;这是控制员的责任。@StephenCleary谢谢您的帮助。我现在明白了,在网上的所有例子中,人们用不同的方式来做,有时ViewModel失去了它的意义,它做的更多。我选择做的是将BusinessService注入控制器,以完成繁重的工作并填充ViewModel。正如下面Daniel提到的,我不需要注入viewmodel,而是在其中实例化并填充。射击
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;
}