数据层:using Dapper;
using ModelLayer;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace DataLayer
{
    public class BookData
    {
        public async Task<IEnumerable<Book>> GetBooks1()
        {
            using (SqlConnection conn =new SqlConnection("xxxx"))
            {
                conn.Open();
                return await conn.QueryAsync<Book>("select bookid,bookname,author from dbo.book",commandType:CommandType.Text);
                //await异步执行
            }
        }
        public Task<IEnumerable<Book>> GetBooks2()
        {
            using (SqlConnection conn = new SqlConnection("xxxx"))
            {
                conn.Open();
                return conn.QueryAsync<Book>("select bookid,bookname,author from dbo.book", commandType: CommandType.Text);
                //同步返回task
            }
        }
    }
}逻辑层:using DataLayer;
using ModelLayer;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;namespace BusinessLayer
{
    public class BookBussinessService
    {
        public async Task<IEnumerable<Book>> GetBooks1_1()
        {
            BookData dal = new BookData();
            /*其他逻辑*/
            return await dal.GetBooks1(); //await异步执行
        }
        public Task<IEnumerable<Book>> GetBooks1_2()
        {
            BookData dal = new BookData();
            /*其他逻辑*/
            return dal.GetBooks1();//同步返回task
        }
        public Task<IEnumerable<Book>> GetBooks2_1()
        {
            BookData dal = new BookData();
            /*其他逻辑*/
            return dal.GetBooks2();//同步返回task
        }
    }
}UI:using System.Collections.Generic;
using System.Threading.Tasks;
using BusinessLayer;
using Microsoft.AspNetCore.Mvc;
using ModelLayer;namespace WebApplication1.Controllers
{
    public class HomeController : Controller
    {
        public async Task<IEnumerable<Book>> GetBooks1()
        {
            BookBussinessService service = new BookBussinessService();
            return await service.GetBooks1_1();
            //view,业务层、数据层都是await执行,会(可能)要启动3个线程异步执行、等待。如果操作简单,线程交互会更耗时间。
        }
        public async Task<IEnumerable<Book>> GetBooks12()
        {
            BookBussinessService service = new BookBussinessService();
            return await service.GetBooks1_2();
            //view,数据层都是await执行,业务层同步返回task.会(可能)要启动2个线程
        }
        public async Task<IEnumerable<Book>> GetBooks2()
        {
            BookBussinessService service = new BookBussinessService();
            return await service.GetBooks2_1();
            //view是await执行,会(可能)要启动1个线程
        }
    }
}上面三类写法,特别是业务层的方法有哪些问题呢?用哪种比较好?

解决方案 »

  1.   

       三层模式实际上已经 趋于淘汰或者 被变异为各种微服务框架 比如,MVP,AOP,DI,MVC等。   微软推荐 .Net MVC 你用这个就行了。 
      

  2.   

    你考虑的所谓启动1个,2个,3个线程,纯粹的多想了。await,async并不是你想的那么简单的启多少个线程。你还需要继续理解一下。
    哪个最好?你可以使用vs的脚手架创建一个mvc5的项目,看看里边是怎么用await async的,它就是微软推荐的方式。就是你的方式1
      

  3.   


    为什么呢?
    因为同步和异步的混合编程,容易造成死锁。
    http://www.knowsky.com/897585.html
      

  4.   

    这两种写法是一样的。定义为 async Task<>  的方法就需要使用 await 来(异步)返回值,而定义为 Task<> 的方法则是返回 Task 然后调用方来决定如何使用 Task(使用 Task.Result 阻塞方式还是异步方式)。async/await 语法是比较具体的,其上一层就是 Task。你的第一、第二种,差别很小。第二种写法灵活一些(调用者决定如何实现调用功能),而第一种写法则具体一些(编译器决定如何实现异步调用功能)。
      

  5.   

    你这写的是什么啊,明明是返回的Task,完了你里面用同步的方法,很明显需要一直await啊
      

  6.   

    第一种。
    async和await并不是简单的启动一个线程。你如果非要理解可以这样理解,在遇到await的时候系统就挂起当前的操作,等待async的返回,返回后继续执行,但是这些操作都被转换到一个线程里了。当然详情并不是这样。但是也不是你想的单纯的启动线程。
      

  7.   

    同步调用:执行方法,等待并接收返回结果,执行下一指令
    异步调用:执行方法并提供回调,执行下一指令(方法结束后通过回调处理结果)
    async await 提供一个语法结构,允许你以同步调用的形式书写异步调用。await 修饰的是回调所以你的几种写法是一样的,何况三层间是有明确分工的,离开约束,将控制从一层的内部进入到另一层的内部,就不是三层,而是大杂烩了
      

  8.   


            //入口
            public async Task<string> GetBooks3()
            {
                await A1();
                return "abc";
            }        public Task A1()
            {
                return A2();
            }
            public Task A2()
            {
                return A3();
            }
            public Task A3()
            {
                var tk = Task.Run(() =>
                {
                    Debugger.Log(0, "", "111111111 \r\n");
                });
                return A4();
            }
            public Task A4()
            {
                var tk= Task.Run(() =>
                {
                    Debugger.Log(0, "", "222222222 \r\n");
                });
                return tk;
            }1、上面的程序,A3、A4中的Task执行顺序是不固定的。也就是意味着:如果一个方法内,包含有两个Task,如果要求先后顺序,则必须都加await。
    2、上面的:public Task<IEnumerable<Book>> GetBooks2()
            {
                using (SqlConnection conn = new SqlConnection("xxxx"))
                {
                    conn.Open();
                    return conn.QueryAsync<Book>("select bookid,bookname,author from dbo.book", commandType: CommandType.Text);
                    //同步返回task
                }
            }在执行时因为是在UI中await的,在执行回调时,using的资源已经释放,会引发错误。
    3、直接返回Task、与返回async Task 需要按照实际业务使用,只是直接返回Task的是同步而已。所以一般为了避免上面2种错误,可以都使用 async Task(即方法内都写await)。而是否开启异步线程则是不一定的(.net运行时会自动处理,怎么处理的原理不明白)。
      

  9.   

    所谓的“//同步返回task”如果知识看见“同步”二字那就是理解上有问题了!返回 Task,则调用方来决定如何使用 Task,可以做到跟 async/await 语法完全一样的异步调用结果。所以 async/await 语法写代码,跟直接返回 Task 的方式,本质上并没有根本区别,只是返回的封装层次不同罢了!!!
      

  10.   

    我认为你的所谓“三层”是典型的“为了三层而三层”的,完全没有必要。你的所谓的"数据层“没有什么意义,你可以直接从业务逻辑层中调用 ADO.NET 来访问数据。就算是将来的 DAL 需要更高级抽象,你也是使用一个更高的 ORM 之类的工具来替换,而不是写你这种所谓的”数据层“——再来重复一遍业务逻辑层方法——的代码。至于你说的"线程”那是想多了。异步方法的代码语法,确实是让人需要多转脑筋,但是异步并不意味着一定是在另一个线程中回调。异步是一种“避免阻塞”的设计思想,并不意味着子线程。
      

  11.   

    特别是有的所谓的“仓储”等等概念,看 “为了三层而三层”的 DAL 概念被戳穿了,于是另外增加一个从 BLL 抽出一堆数据库(有可能)沾边的操作集中在一个模块中定义和写实现代码。实际上你的业务逻辑层应该直接了当地调用一个非常专业的数据库引擎,数据库引擎不应该围绕这业务逻辑而自己定义这部分代码。你要是开发DAL层代码,那么你就封装SQLHelper、或者自己研发 ORM 等等。总之自己写的 DAL 层应该跟逻辑无关,不可以相互纠缠二者、一旦业务改变了就去改变DAL代码。
    所以你的两个问题其实都比较“轻”:
    第一个,返回 Task 和 async/await 语法两种形式,其实本质上是一样的。返回 Task 则意味着调用方来决定是阻塞获取 result 还是使用 Task 的异步方法(包括调用方使用 wait 语法)来使用它。而定义为 async/await 语法则强迫所有调用这类方法的代码也必须写成 async/await 的i形式。只有这个区别。第二个,其实那你的业务逻辑层应该直接调用成熟的数据库引擎来操作数据库,既然已经有了多种成熟的 DAL 引擎框架直接用就好了,不要自己写什么 DAL 代码,尤其不要围绕着 BLL 类型来胡乱写什么 DAL 代码。