Aggregate Services
https://stackoverflow.com/questions/7199097/constructor-injection-into-a-base-class-using-autofac
Calling the base class constructor explicitly is the only way to do this using constructor injection in C#. It looks like you should remove the parameterless constructors from BaseController
and PublicController
as they should never actually be called when a logger is available.
The problem of injecting dependencies into a base controller is a common one using ASP.NET MVC and IoC. There are several options/schools of thought.
1.) Use aggregate services. To keep derived class constructors simple, create a single service that exposes or delegates to all the different services needed by the base controller (e.g. IBaseControllerDependencies
or similar.) Then pass this one service to the BaseController
just as you are doing with ILogger
here.
There are various pros/cons depending on your application and the number of base classes you're using. Google for 'Autofac aggregate services' to see more on this.
2.) Use property injection. Make the ILogger
property on your base class public, and configure the container using:
builder.RegisterControllers().PropertiesAutowired();
Property injection isn't really a preferred technique in Autofac. The constructor's role is to accept dependencies, while writeable properties are often seen as a code smell, so Autofac doesn't really optimise for this case. One of the drawbacks is that writeable properties that shouldn't be injected often are mistakenly, with odd consequences.
3.) Refactor base controller functionality into various action filters. Autofac can inject action filters into the MVC action invocation pipeline. Thus the filters can take the dependencies that were on the base class, and the same concerns might be applied in a cross-cutting way. More info on this out on the web, ExtensibleActionInvoker
and .InjectActionInvoker()
point to the info you'd need. Not always possible with all concerns.
4, also the answer to your second question.) Resolve base controller dependencies using service location from DependencyResolver.Current
.
var logger = DependencyResolver.Current.GetService<ILogger>();
The reason this isn't encouraged is that it makes the resulting application harder to understand because it is no longer possible to see what services a component depends upon by looking in one place (the constructor.) To determine what must be configured in the container before a particular component can be used, one has to look at the entire codebase of the component to find the GetService()
calls. A noticeable impediment when unit testing.
Hope this helps, bit of a brain dump I know :) Others can probably add some more ideas to these.
Refactoring dependencies with Autofac Aggregate Services 如何使用
Aggregate Services autofac官方文档
Introduction
An aggregate service is useful when you need to treat a set of dependencies as one dependency. When a class depends on several constructor-injected services, or have several property-injected services, moving those services into a separate class yields a simpler API.
An example is super- and subclasses where the superclass have one or more constructor-injected dependencies. The subclasses must usually inherit these dependencies, even though they might only be useful to the superclass. With an aggregate service, the superclass constructor parameters can be collapsed into one parameter, reducing the repetitiveness in subclasses. Another important side effect is that subclasses are now insulated against changes in the superclass dependencies, introducing a new dependency in the superclass means only changing the aggregate service definition.
The pattern and this example are both further elaborated here.
Aggregate services can be implemented by hand, e.g. by building a class with constructor-injected dependencies and exposing those as properties. Writing and maintaining aggregate service classes and accompanying tests can quickly get tedious though. The AggregateService extension to Autofac lets you generate aggregate services directly from interface definitions without having to write any implementation.
Required References
You can add aggregate service support to your project using the Autofac.Extras.AggregateService NuGet package or by manually adding references to these assemblies:
- Autofac.dll
- Autofac.Extras.AggregateService.dll
- Castle.Core.dll (from the Castle project)
Getting Started
Lets say we have a class with a number of constructor-injected dependencies that we store privately for later use:
public class SomeController
{
private readonly IFirstService _firstService;
private readonly ISecondService _secondService;
private readonly IThirdService _thirdService;
private readonly IFourthService _fourthService; public SomeController(
IFirstService firstService,
ISecondService secondService,
IThirdService thirdService,
IFourthService fourthService)
{
_firstService = firstService;
_secondService = secondService;
_thirdService = thirdService;
_fourthService = fourthService;
}
}
To aggregate the dependencies we move those into a separate interface definition and take a dependency on that interface instead.
public interface IMyAggregateService
{
IFirstService FirstService { get; }
ISecondService SecondService { get; }
IThirdService ThirdService { get; }
IFourthService FourthService { get; }
} public class SomeController
{
private readonly IMyAggregateService _aggregateService; public SomeController(IMyAggregateService aggregateService)
{
_aggregateService = aggregateService;
}
}
Finally, we register the aggregate service interface.
using Autofac;
using Autofac.Extras.AggregateService;
//... var builder = new ContainerBuilder();
builder.RegisterAggregateService<IMyAggregateService>();
builder.Register(/*...*/).As<IFirstService>();
builder.Register(/*...*/).As<ISecondService>();
builder.Register(/*...*/).As<IThirdService>();
builder.Register(/*...*/).As<IFourthService>();
builder.RegisterType<SomeController>();
var container = builder.Build();
The interface for the aggregate service will automatically have an implementation generated for you and the dependencies will be filled in as expected.
遇到如下问题
{
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred when trying to create a controller of type 'CodeStocksController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Type 'LISA.WebApi.Chile.Controllers.CodeStocksController' does not have a default constructor",
"ExceptionType": "System.ArgumentException",
"StackTrace": " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
排查之后发现是没有正确使用Owin和web api导致的
https://autofaccn.readthedocs.io/en/latest/integration/webapi.html#get-the-httpconfiguration
https://autofaccn.readthedocs.io/en/latest/integration/webapi.html#owin-integration
A common error in OWIN integration is use of the GlobalConfiguration.Configuration
. In OWIN you create the configuration from scratch. You should not reference GlobalConfiguration.Configuration
anywhere when using the OWIN integration.
扩展阅读
Dependency Injection and Class Inheritance 官方文档提到的一篇文章
Refactoring to Aggregate Services 最原始的讨论
Aggregate Services的更多相关文章
- .NetCore外国一些高质量博客分享
前言 我之前看.netcore一些问题时候,用bing搜索工具搜到了一些外国人的博客.翻看以下,有学习的价值,就分享在这里了. 个人博客 andrewlock.net 最新几篇如下,一看标题就知道很有 ...
- Package Manager Console的使用
Find-Package PM> Find-Package autofac https://docs.microsoft.com/en-us/nuget/tools/ps-ref-find-pa ...
- NetCore博客
NetCore外国一些高质量博客 https://www.cnblogs.com/fancunwei/p/9605627.html 前言 我之前看.netcore一些问题时候,用bing搜索工具搜到了 ...
- (转载)SQL Reporting Services (Expression Examples)
https://msdn.microsoft.com/en-us/library/ms157328(v=SQL.100).aspx Expressions are used frequently in ...
- 【HANA系列】SAP HANA XS使用Data Services查询CDS实体【二】
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用Dat ...
- [Windows Azure] How to Monitor Cloud Services
How to Monitor Cloud Services To use this feature and other new Windows Azure capabilities, sign up ...
- spring boot 打包方式 spring boot 整合mybaits REST services
<build> <sourceDirectory>src/main/java</sourceDirectory> <plugins> <plugi ...
- Smart internet of things services
A method and apparatus enable Internet of Things (IoT) services based on a SMART IoT architecture by ...
- 【HANA系列】【第八篇】SAP HANA XS使用Data Services查询CDS实体【二】
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第八篇]SAP HANA XS ...
随机推荐
- LightOJ - 1422 (Halloween Costumes)
题目链接:传送门 题目大意:要参加聚会,对应聚会要穿对应衣服,衣服可以套着穿,也可以脱下来,但脱下来之后不能再穿,问参加完所有聚会至少需要几件衣服? 题目思路:区间DP 一开始自己没有想出来状态转移方 ...
- 51NOD 1013(3的幂的和)
题目链接:传送门 题目大意:求(3^0+3^1+3^2+3^3+...+3^n)%1e9的值 题目思路:乘法逆元裸题 #include <iostream> #include <cs ...
- Visualizing mathematical functions by generating custom meshes using FireMonkey(很美)
Abstract: This article discusses how you can generate your own 3-dimensional mesh for visualizing ma ...
- 数据库字符集(AL32UTF8)和客户端字符集(2%)是不同的
登录oracle数据库时我们会遇到这样的提示信息:“数据库字符集(AL32UTF8)和客户端字符集(2%)是不同的”. 这是由于数据库服务端和客户端的字符集不一致所造成的,服务端字符集和客户端字符集相 ...
- MySQL 如何利用一条语句实现类似于if-else条件语句的判断
一. 编写一条update语句实现商品涨价,具体规则如下 1.99元以内,提价20% 2.100-999元之间,提价10% 3.1000-1999之间,提价5% 4.其他提价2% update goo ...
- Collections工具类的使用
创建实体类 public class News implements Comparable { private int id; //新闻编号 private String title; //新闻标题 ...
- php smarty模板引擎
<?php /* 一.什么是smarty? smarty是一个使用PHP写出来的模板PHP模板引擎,它提供了逻辑与外在内容的分离,简单的讲, 目的就是要使用PHP程序员同美工分离,使用的程序员改 ...
- Python3+Selenium3自动化测试-(一)
完成环境的安装并测试之后,我们对Selenium有了一定的了解了,接下来我们继续驱动浏览器做一些基本操作: 窗口尺寸设置.网页截图.刷新.前进和后退 窗口尺寸设置 在测试过程中,我们可能会要求打开浏览 ...
- 部门人员能力模型的思考:海军 or 海盗——By Me
我们欢迎您的加入,与我们一起推动安全可视化团队的成长,实现技术上共同进步和感情上的更多互相支持!
- 011-JDK可视化监控工具-Jstat
一.概述 Jstat 是JDK自带的一个轻量级小工具.全称“Java Virtual Machine statistics monitoring tool”,它位于java的bin目录下,主要利用JV ...