2016-10-08 5 views
1

Я пытаюсь понять, как DI работает в новом ASP Core. С помощью учебника я сделал это для контроллеров, но не могу заставить его работать для моделей. Например, у меня есть AuthController, и я применил к нему контекст базы данных, но теперь, когда у меня больше контроллеров, использующих одну и ту же модель, которая равна Authentication, я хотел бы добавить контекст к самой модели. Вот некоторые кусок кода, который я:ASP.NET CORE DI в модели

Из Startup.cs

public void ConfigureServices(IServiceCollection services) 
{ 
    ... 
    services.AddDbContext<GameContext>(options => options.UseSqlServer(@"Data Source=DESKTOP-USER\SQLEXPRESS;Initial Catalog=Db7;Integrated Security=True;Connect Timeout=30;")); 
} 

И вот как я использовал его с контроллерами:

[Route("api/[controller]")] 
public class AuthController : Controller 
{ 
    public GameContext db; 
    public AuthController(GameContext context) 
    { 
     db = context; 
    } 

    [HttpPost] 
    [Route("login")] 
    public LoginResponseModel Login([FromBody] LoginModel user) //public Models.VM.LoginModel Login([FromBody] Models.VM.LoginModel user) 
    { 
     //query user 
     var detectedUser = db.Users.FirstOrDefault(u => u.Email == user.Email && u.Password == HelperClass.Md5(user.Password); 

Если удалить контекстную часть из контроллера, и переместите его в модель, я не смогу его снова установить, так как конструктору нужен аргумент (который будет введен автоматически)

public class Authentication 
{ 
    public GameContext db; 

    public Authentication(GameContext context) 
    { 
     db = context; 
    } 
    ... 

Как я могу добраться до базы данных из модели?

EDIT:

Это как мой класс аутентификации будет выглядеть (конструктор может выглядеть по-разному на основе решения):

public class Authentication 
{ 
    public GameContext db; 

    public Authentication(GameContext context) 
    { 
     db = context; 
    } 

    public LoginResponseModel Login(LoginModel user) 
    { 
     //query user 
     var detectedUser = db.Users.FirstOrDefault(u => u.Email == user.Email && u.Password == HelperClass.Md5(user.Password)); 

И вот как я хотел бы использовать эту модель из контроллеры:

[Route("api/[controller]")] 
public class AuthController : Controller 
{ 

    public AuthController(GameContext context) 
    { 
    } 

    // POST api/login 
    [HttpPost] 
    [Route("login")] 
    public LoginResponseModel Login([FromBody] LoginModel user) //public Models.VM.LoginModel Login([FromBody] Models.VM.LoginModel user) 
    { 
     Authentication auth = new Authentication(); //throws error since no parameter passed 

     return auth.Login(user); 
    } 
+0

Как вы собираетесь создавать экземпляр модели? Попытка понять, как вы собираетесь использовать модель. ваше объяснение было непонятным. Вы заменяете контекст в конструкторе контроллера моделью? – Nkosi

+0

добавил дополнительную информацию –

+1

Хорошо, я думаю, теперь понимаю. составление ответа – Nkosi

ответ

2

Вы в основном делаете многоразовое обслуживание для других контроллеров.

Начните с создания абстракции требуемой функциональности.

public interface IAuthenticationService { 
    LoginResponseModel Login(LoginModel user); 
} 

и иметь реализацию наследуют этот интерфейс

public class Authentication : IAuthenticationService { 
    private readonly GameContext db; 

    public Authentication(GameContext context) { 
     db = context; 
    } 

    public LoginResponseModel Login(LoginModel user) { 
     //query user 
     var detectedUser = db.Users.FirstOrDefault(u => u.Email == user.Email && u.Password == HelperClass.Md5(user.Password)); 
     //...other code that creates and returns an instance of LoginResponseModel 
    } 
} 

с, что на месте вам нужно зарегистрировать интерфейс с коллекцией услуг, с тем, что структура DI знает о том, что вводить каждый раз, когда он видит, этот интерфейс.

Источник: Asp.Net Core Fundamentals: Dependency Injection

public void ConfigureServices(IServiceCollection services) { 
    ... 
    services.AddDbContext<GameContext>(options => options.UseSqlServer(@"Data Source=DESKTOP-USER\SQLEXPRESS;Initial Catalog=Db7;Integrated Security=True;Connect Timeout=30;")); 
    // Add application services. 
    services.AddTransient<IAuthenticationService, Authentication>(); 
} 

и теперь любой контроллер, который необходим доступ к сервису может быть он вводится в его конструктор

[Route("api/[controller]")] 
public class AuthController : Controller { 
    private readonly IAuthenticationService auth; 

    public AuthController(IAuthenticationService auth) { 
     this.auth = auth; 
    } 

    // POST api/login 
    [HttpPost] 
    [Route("login")] 
    public LoginResponseModel Login([FromBody] LoginModel user) { 
     return auth.Login(user); 
    } 
} 

Каркас DI будет обрабатывать всю тяжелую создания и инъекции услуги. Теперь вам не нужно создавать экземпляры самостоятельно.

+0

спасибо за решение, работает очень хорошо! +1 для четкого и приятного объяснения. Один вопрос может быть глупым, но пока не видно причины: зачем нужно регистрировать IAuthenticationService как услугу? –

+1

Чтобы среда DI была осведомлена о том, что нужно вводить, когда он видит этот интерфейс. Проверьте документацию здесь https://docs.asp.net/ru/latest/fundamentals/dependency-injection.html. – Nkosi

Смежные вопросы