.NET CORE中控制器、服务构造函数必须Public

因为在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用的服务。

 

posted @ 2021-02-10 10:41  ZedFFF  阅读(361)  评论(0)    收藏  举报