因为在core中依赖注入是很自然发生的一件事,并且建议实现的方式是通过构造函数注入服务,所以一般我们的服务首先会继承一个服务接口,
服务接口内部写了固定的类似增删改查的约定
然后针对某个功能也就是控制器再实例化对应的服务,控制器内部存储服务的接口,完全与具体的服务对象分离。
就像这样:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using WebAppTest1.Models; using WebAppTest1.Services; namespace WebAppTest1.Controllers { public class TodoController : Controller { //实例化服务 private readonly ITodoItemService _todoItemService; public TodoController(ITodoItemService todoItemService) { _todoItemService = todoItemService; } public async Task<IActionResult> Index() { var items = await _todoItemService.GetIncompleteItemsAsync(); var model = new TodoViewModel() { Items = items }; return View(model); } public async Task<IActionResult> AddItem(TodoItem todoItem) { if (!ModelState.IsValid) { return RedirectToAction(nameof(Index)); } var isSuccessful = await _todoItemService.AddItemAsync(todoItem); if(!isSuccessful) { return BadRequest("Could not add Item"); } return RedirectToAction(nameof(Index)); } } }
可以看到Todo控制器是显示的声明了构造函数,并且接受ITodoItemService的参数,用于传递给控制器自身的_todoItemService服务成员。
而具体的服务是这么实现的
using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using WebAppTest1.Data; using WebAppTest1.Models; namespace WebAppTest1.Services { public class TodoItemService : ITodoItemService { private readonly ApplicationDbContext _context; //通过构造函数注入服务 public TodoItemService(ApplicationDbContext context) { _context = context; } public async Task<bool> AddItemAsync(TodoItem newItem) { newItem.Id = Guid.NewGuid(); newItem.IsDone = false; newItem.DueAt = DateTimeOffset.Now.AddDays(3); await _context.AddAsync(newItem); var saveResult = await _context.SaveChangesAsync(); return saveResult == 1; } public Task<TodoItem[]> GetIncompleteItemsAsync() { Task<TodoItem[]> res = _context.TodoItems.Where(x => x.IsDone == false).ToArrayAsync(); return res; } } }
也可以看到几乎和控制器的实现思路是一致的,因此为了让依赖注入能被实现,需要我们将注入的方法,在这里是构造函数声明为public。
那么最初的注入是在哪里声明的呢
在Startup类中
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); //服务注入 //services.AddSingleton<ITodoItemService, FakeTodoItemService>(); services.AddScoped<ITodoItemService, TodoItemService>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite( Configuration.GetConnectionString("ApplicationDbContext"))); }
这里可以看到我增加了TodoItemService和ApplicationDbContext两个服务,一个是具体的业务,另一个是链接sqllite用的服务。