简体   繁体   English

服务层依赖注入

[英]Service Layer Dependency Injection

I am creating a Web API that would call a service layer, and I am trying to learn Dependency Injection, ( i am hoping to use ninject), but I am unsure on how to create dependency on the service layer. 我正在创建一个将调用服务层的Web API,并且尝试学习依赖注入(我希望使用ninject),但是我不确定如何在服务层上创建依赖关系。

This is what the web api would call. 这就是Web API所要调用的。

在此处输入图片说明

Here the issues, when calling IPersonService, the person would have a gender defined, it would have a name, a role, and ethnicity. 这里的问题是,在调用IPersonService时,该人员将定义性别,名称,角色和种族。 I am using constructor injection and unsure if I should call the GenderService or should I call the business layer ( in this case defined by Core). 我正在使用构造函数注入,不确定是否应该调用GenderService还是应该调用业务层(在这种情况下,由Core定义)。

在此处输入图片说明

Should I be calling the service like the picture above, or below 我应该像上图还是下图那样致电服务

在此处输入图片说明

This is what my person service look like 这就是我的人事服务的样子

namespace Service.Services
{
    public class PersonService : IPersonService
    {
        private IPersonCore personCore = null;
        private INameService nameService = null;
        private IRoleService roleService = null;
        private IGenderService genderService = null;
        private IEthnicityService ethnicityService = null;
        private IPrefixService prefixService = null;
        private Person currUser;

        public PersonService(IPersonCore _personcore, INameService _namecore, IRoleService _roleservice, IGenderService _genderservice, IEthnicityService _ethnicityservice, IPrefixService _prefixservice )
        {
            this.personCore = _personcore;
            this.nameService = _namecore;
            this.roleService = _roleservice;
            this.genderService = _genderservice;
            this.ethnicityService = _ethnicityservice;
            this.prefixService = _prefixservice;
        }

        public IEnumerable<Person> GetAllPerson()
        {
            if (isAuthorized())
            {
                return this.personCore.GetPersons();
            }
            return null;
        }

        public Person GetPersonByID(int id)
        {
            if (isAuthorized())
            {
                return this.personCore.GetPersonByID(id);
            }
            return null;
        }

        public Person GetPersonByEmail(string email)
        {
            if (isAuthorized())
            {
                return this.personCore.GetPersonByEmail(email);
            }
            return null;
        }

        public IEnumerable<Person> GetPersonByName(string first, string last, string middle)
        {
            if(isAuthorized())
            { 
                Name newname = this.nameService.CreateName(first, last, middle);
                return this.personCore.GetPersonByName(newname);
            }
            return null;
        }

        public IEnumerable<Person> GetPersonWithRoles(IEnumerable<Roles> r)
        {
        }

        public IEnumerable<Person> GetPersonWithDOB(DateTime d)
        {
            if (isAuthorized())
            {
                return this.personCore.GetPersonWithDOB(d);
            }
            return null;
        }

        public Person SetPersonRole(int id, Roles r)
        {
        }

        public Person SetGender(int id, Gender g)
        {
        }

        public Person SetEthnicity(int id, Ethnicity e)
        {
        }

        public Person SetPrefix(int id, Prefix p)
        {
        }

        public Person CreatePerson(Person p)
        {
            if (isAuthorized())
            {
                return personCore.AddPerson(p);
            }
            return null;
        }

        public Person UpdatePerson(Person p)
        {
            if (isAuthorized())
            {
                return personCore.UpdatePerson(p);
            }
            return null;
        }

        public Person ActivatePerson(int id)
        {
            if (isAuthorized())
            {
                return personCore.ActivatePerson(id);
            }
            return null;
        }

        public Person DeactivatePerson(int id)
        {
            if (isAuthorized())
            {
                return personCore.DeactivatePerson(id);
            }
            return null;
        }

        public bool DeletePerson(int id)
        {
            if (isAuthorized())
            {
                return personCore.DeletePerson(id);
            }
            return false;
        }

        protected bool isAuthorized()
        {
            //Probably move to common
            return true;
        }
    }
}

When calling from the Web API my issue with it, is its sound like a lot of dependency for finding something about a certain person. 从Web API调用时,我的问题是,它听起来很依赖于查找某个人的东西。

The PersonService class contains many dependencies, because you are violating the Single Responsibility Principle . PersonService类包含许多依赖项,因为您违反了“ 单一职责原则” This class has many responsibilities and you'll end up changing this class every time you are adding a new feature (which is a Open/Closed Principle violation). 此类有很多责任,每次添加新功能(违反开放式/封闭式原理 )时,您都将不得不更改此类。 Besides, the isAuthorized method is a cross-cutting concern, which this class should have no notion of. 此外, isAuthorized方法是一个横切关注点,此类不应该涉及任何概念。

On top of that, you are injecting the current logged in user into the PersonService . 最重要的是,您正在将当前登录的用户注入PersonService This is runtime data, and constructing application components using runtime data is an anti-pattern . 这是运行时数据, 使用运行时数据构造应用程序组件是一种反模式

There are many ways to fix this, but it all comes down to understanding the SOLID principles. 有很多方法可以解决此问题,但这全都在于理解SOLID原理。 Doing so however might be a daunting task, especially if you're just starting with DI and software design. 但是,这样做可能会是一项艰巨的任务,特别是如果您刚开始使用DI和软件设计。 There are many books you can read about this, such as the amazing work from Robert C. Martin and books about Dependency Injection like Mark Seemann's Dependency Injection in .NET . 您可以阅读许多关于此的书籍,例如Robert C. Martin 的出色著作和有关依赖注入的书籍,例如Mark Seemann 在.NET中依赖注入

Designs that helped me out a lot the last few years are message based architectures, where use cases are described by messages, and implementations are described by generic abstractions (read this and this ). 最近几年对我有很大帮助的设计是基于消息的体系结构,用例通过消息描述用例,而实现则通过通用抽象描述(请阅读thisthis )。 These designs have proven to be very flexible and maintainable, since they allow adding cross-cutting concerns transparently and allow adding new features without changing any existing code. 这些设计被证明是非常灵活和可维护的,因为它们允许透明地添加横切关注点,并允许在不更改任何现有代码的情况下添加新功能。 Such design also allows reducing your Web API layer to a simple piece of infrastructure that doesn't require changing when new features are being added. 这种设计还可以将您的Web API层简化为一个简单的基础架构,在添加新功能时不需要更改。 You can read about this concept here (note: that article is about WCF, but the concept for Web API is the same) and here is a Github repository that shows how to implement this both in WCF and Web API. 您可以在此处阅读有关此概念的信息 (注意:该文章是关于WCF的,但是Web API的概念是相同的),并且这里是Github存储库,显示了如何在WCF和Web API中实现此概念。

I wish you the best of luck in your quest to software mastery. 祝您在掌握软件方面万事如意。

You can simplify this in 2 ways: 您可以通过两种方式简化此操作:

  1. Your PersonService does not look to depend itself on the Role, Gender, Ethnicity and Prefix services as you do not call them from its methods. 您的PersonService不会依赖于角色,性别,种族和前缀服务,因为您不会从其方法中调用它们。 It's rather a shell that your client code calls instead of calling directly these services themselves. 您的客户端代码调用的是一个外壳,而不是直接自己调用这些服务。 If that is the case, then you can simplify your PersonService by getting these 4 dependencies out: 如果是这种情况,那么可以通过除去以下4个依赖项来简化PersonService:

     private IRoleService roleService = null; private IGenderService genderService = null; private IEthnicityService ethnicityService = null; private IPrefixService prefixService = null; 

    And these methods out to their respective services: 并将这些方法提供给它们各自的服务:

     public Person SetPersonRole(int id, Roles r) { } public Person SetGender(int id, Gender g) { } public Person SetEthnicity(int id, Ethnicity e) { } public Person SetPrefix(int id, Prefix p) { } 
  2. If you need absolutely to keep these methods inside your IPersonService, then you would inject the dependencies in the methods rather than the constructor. 如果绝对需要将这些方法保留在IPersonService中,则可以将依赖项注入方法而不是构造函数中。

    Regarding the dependency on the Service or the Core, it depends on what your service does. 关于对服务或核心的依赖性,取决于您服务的功能。 If your service is just calling the Core, then go to the Core yourself. 如果您的服务只是调用Core,请自己转到Core。 If your Service is doing some validation or anything else, you may want to depend on it to avoid copying the same code in the PersonService. 如果您的服务正在执行某种验证或其他任何验证,则可能需要依赖它以避免在PersonService中复制相同的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM