MVC 简单框架起步-分层(二)

       框架当然离不开分层,最开始写 Hello Word 第一个程序,很简单,完全不需要其他,直接Console.Write() 一下就好。后来需要实现一个小小的9*9乘法表,直接在一个方法在里面实现,可当我们实现一个业务的时候,可能要个100行左右的代码量,将此这个业务拆分成几个方法块,然后进行组合调用,这样做的目的也是解耦,为了以后需求变更时更好的拓展,分层也是这个目的,常见的一般时 数据访问层DLL,业务数据层BLL,模型层Model,UI层,有时候还会有一个帮助层,和接口层,这些层之间关系如下       

                            

 

 这种实现方式看起来很基础,感觉和 最开始 拆分方法很类似,用的时候 New 一下,不过是方法放在同一个类库下,而分层是在一个新的类库中,另外要把类库生成 dll 添加进来。综合来看依赖性依旧很强,所以需要进行调整,采用控制反转的方式来解除强依赖关系,这里采用AutoFac 的技术来实现,调整后的框架结构如下:

        

 

如上,接入 AutoFac (IOC) 后,就不必进行大量的New 操作,需要那个方法,直接通过接口向容器拿就好。只需要将 BLL,DLL层的接口继承 IDependency接口,然后在全局文件Global中 进行注册。对于用惯了 New 方式的人来说,代码简直优美的不行,当然对于IOC 控制反转 的工具有很多,像 微软自带的 MEF,和其他的第三方工具 AutoFac ,Unity、Spring.NET、StructureMap 等等,这里主推AutoFac 实现简单,好理解,效率高,我之前有用过微软自带的 MEF,也就那样,直到尝试了AutoFac,果然主流的东西还是更香一些。

关于AutoFac 如何使用,这里做一个简要的说明,网上很多文章,说的不明不白,浅藏辄止,举几个简单的例子,感觉很简单,实际在项目使用的时候疑惑的地方很多。

1. 如何批量注册IBLL 和IDLL层

2. 同一个接口被多个类继承并实现,调用的时候如何区分

3. 网上大多是Web层 直接通过容器调用DLL层,那么当web调用BLL层,BLL去调用DLL层时,BLL如何关联DLL层

这些问题对于熟悉容器的人来说可能不值一提,但对于小白来说,很是纠结,一度迷惑了我很久。试想带着很多疑问去学习,或者说是不理解。这就是一根坎,总有一些路要独自一个人走,能走多远,走多快全靠自己领悟,如果没有领路人真的是费劲。这里记录一下

1. 实际项目中,不可能挨个接口去注册,不现实,这里只需要定义一个公共接口类,让IBLL层,IDLL层 均继承此接口,然后再全局文件Global.asax 中注册此公共接口即可

  

            #region AtuoFac 注册

            Assembly[] assemblies = Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath, "*.dll").Select(Assembly.LoadFrom).ToArray();
            //创建autofac管理注册类的容器实例
            var builder = new ContainerBuilder();
            //注册所有实现了 IDependency 接口的类型
            Type baseType = typeof(IDependency);
            builder.RegisterAssemblyTypes(assemblies)
            //.Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract || type.GetCustomAttribute(typeof(ServiceAttribute)) != null)
            .Where(t => baseType.IsAssignableFrom(t) || baseType.IsAssignableFrom(t) && !t.IsAbstract)
            .AsSelf().AsImplementedInterfaces()
            .PropertiesAutowired().InstancePerLifetimeScope();

            //使用Autofac提供的RegisterControllers扩展方法来对程序集中所有的Controller一次性的完成注册
            builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
            builder.RegisterFilterProvider();
            //生成具体的实例
            var container = builder.Build();
            //下面就是使用MVC的扩展 更改了MVC中的注入方式.
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));


            #endregion

 

2. 当同一个接口被多个类继承并实现时,按照常规,用接口对象去调用时,默认是后一个被注册的实现类覆盖前一个实现类。如果想区分开,可以采用 Attribute 特性的方式给实现类分别加上不同的名称,写一个根据特性名找对应实现类的公共方法,调用此方法即可

3. 对于Web 层直接调用 DLL 层来说,很简单,直接添加接口对象,然后再构造函数中,赋值接口对象即可。当通过BLL 层来实现此方式时,需要做一个转变,我们先在BaseLL 层的基类中定义BaseDLL 为null

    public class BaseBLL<T> : IBaseBLL<T> where T : class, new()
    {
        //定义BasaDLL为 null
        protected IBaseDLL<T> BaseDLL = null;

        public int Add(T model)
        {
            return BaseDLL.Add(model);
        }
    }

然后在BLL业务实现类中的构造函数中对 该业务实现类对应的 数据访问类接口对象进行赋值,以及该业务实现类的基类进行赋值,具体赋值操作如下

    public class MenuBLL:BaseBLL<Menu>,IMenuBLL
    {
        IMenuDLL MenuDLL { set; get; }
        public MenuBLL(IMenuDLL dLL)
        {
            BaseDLL = dLL;
            MenuDLL = dLL;
        }
    }

如此,需要调用函数时候,用同样的方式在控制器所在的构造函数中进行赋值,便可以通过容器任意调用BLL层中的函数

    public class HomeController : Controller
    {
        public IMenuBLL MenuBLL { set; get; }
        public HomeController(IStudentBLL bLL)
        {
            MenuBLL = menuBLL;
        }

       .....

     }

 

posted @ 2020-06-30 22:33  郎中令  阅读(295)  评论(0编辑  收藏  举报