如何使用Autofac和ASP.NET Core在控制器上启用属性注入?

时间:2016-05-18 12:09:56

标签: asp.net-core autofac asp.net-core-mvc

似乎没有一种简单的方法可以确保控制器具有属性注入。

解决这个问题的方法是单独注册所有控制器,这似乎有点失败了。 Sub TU_Levenshtein() Call Levenshtein("democrat", "republican") Call Levenshtein("ooo", "u") Call Levenshtein("ceci est un test", "ceci n'est pas un test") End Sub Sub Levenshtein(ByVal string1 As String, ByVal string2 As String) ' Fill Matrix Levenshtein (-> array 'Distance') Dim i As Long, j As Long Dim string1_length As Long Dim string2_length As Long Dim distance() As Long string1_length = Len(string1) string2_length = Len(string2) ReDim distance(string1_length, string2_length) For i = 0 To string1_length distance(i, 0) = i Next For j = 0 To string2_length distance(0, j) = j Next For i = 1 To string1_length For j = 1 To string2_length If Asc(Mid$(string1, i, 1)) = Asc(Mid$(string2, j, 1)) Then distance(i, j) = distance(i - 1, j - 1) Else distance(i, j) = Application.WorksheetFunction.min _ (distance(i - 1, j) + 1, _ distance(i, j - 1) + 1, _ distance(i - 1, j - 1) + 1) End If Next Next LevenshteinDistance = distance(string1_length, string2_length) ' for information only ' Write Matrix on VBA sheets (only for visuation, not used in calculus) Cells.Clear For i = 1 To UBound(distance, 1) Cells(i + 2, 1).Value = Mid(string1, i, 1) Next i For i = 1 To UBound(distance, 2) Cells(1, i + 2).Value = Mid(string2, i, 1) Next i For i = 0 To UBound(distance, 1) For j = 0 To UBound(distance, 2) Cells(i + 2, j + 2) = distance(i, j) Next j Next i ' One solution current_posx = UBound(distance, 1) current_posy = UBound(distance, 2) Do cc = distance(current_posx, current_posy) Cells(current_posx + 1, current_posy + 1).Interior.Color = vbYellow ' visualisation again ' Manage border case If current_posy - 1 < 0 Then MsgBox ("deletion. " & Mid(string1, current_posx, 1)) current_posx = current_posx - 1 current_posy = current_posy GoTo suivant End If If current_posx - 1 < 0 Then MsgBox ("insertion. " & Mid(string2, current_posy, 1)) current_posx = current_posx current_posy = current_posy - 1 GoTo suivant End If ' Middle cases cc_L = distance(current_posx, current_posy - 1) cc_U = distance(current_posx - 1, current_posy) cc_D = distance(current_posx - 1, current_posy - 1) If (cc_D <= cc_L And cc_D <= cc_U) And (cc_D = cc - 1 Or cc_D = cc) Then If (cc_D = cc - 1) Then MsgBox "substitution. " & Mid(string1, current_posx, 1) & " by " & Mid(string2, current_posy, 1) current_posx = current_posx - 1 current_posy = current_posy - 1 GoTo suivant Else MsgBox "no operation" current_posx = current_posx - 1 current_posy = current_posy - 1 GoTo suivant End If ElseIf cc_L <= cc_D And cc_L = cc - 1 Then MsgBox ("insertion. " & Mid(string2, current_posy, 1)) current_posx = current_posx current_posy = current_posy - 1 GoTo suivant Else MsgBox ("deletion." & Mid(string1, current_posy, 1)) current_posx = current_posx current_posy = current_posy - 1 GoTo suivant End If suivant: Loop While Not (current_posx = 0 And current_posy = 0) End Sub 属性为removed,他们特别提到应该由各个IoC容器决定这一点。

我错过了一些明显的东西吗?查找所有可用的扩展方法,但没有找到任何内容,相同的问题和讨论论坛。

2 个答案:

答案 0 :(得分:1)

是的,使用autofac为控制器设置属性注入有点棘手;),但这是它的工作原理。

使用ASP.NET Core(2.1),首先需要在Startup.cs中将控制器注册为服务:

services.AddMvc().AddControllersAsServices();

否则,属性注入将无法如autofac docs中所述:

  

默认情况下,ASP.NET Core会从容器中解析控制器参数,但实际上不会从容器中解析控制器。这通常不是问题,但是它的意思是:[...] 您在控制器注册过程中可能进行的特殊接线(例如设置属性注入)将不起作用 >

然后,您需要通过populate向autofac容器构建器注册服务,然后,您可以向autofac容器注册控制器。

这是autofac docs的简短代码摘录:

  public IServiceProvider ConfigureServices(IServiceCollection services)
  {
    services.AddMvc().AddControllersAsServices();
    var builder = new ContainerBuilder();
    builder.Populate(services);
    builder.RegisterType<MyController>().PropertiesAutowired();
    this.ApplicationContainer = builder.Build();
    return new AutofacServiceProvider(this.ApplicationContainer);
  }

请务必附加.PropertiesAutowired()以便进行属性注入!

现在另一件事可能并不明显,那就是autofac的PropertiesAutowired不会自动将服务的每个属性视为属性注入的麻烦。

github source code中检出DefaultPropertySelector,您会看到它会跳过非公开的内容:

if (!propertyInfo.CanWrite || propertyInfo.SetMethod?.IsPublic != true)
{
    return false;
}

因此,您可能需要创建自定义PropertySelector来扩展DefaultPropertySelector,以便根据自己的逻辑将属性注册为可注入的。因此,您可以执行以下操作:

var propSelector = new MyPropertySelector();
builder.RegisterType<MyController>().PropertiesAutowired(propSelector);

为了确保您不必总是记住每个控制器类,还可以批量注册所有控制器:

builder.Populate(services);
var propSelector = new MyPropertySelector();
builder
  .RegisterAssemblyTypes(typeof(Controller).Assembly)
  .AssignableTo<Controller>()
  .InstancePerLifetimeScope()
  .PropertiesAutowired(propSelector);

希望这会有所帮助:)

答案 1 :(得分:1)

我试过了

builder.Populate(services);
var propSelector = new MyPropertySelector();
builder
  .RegisterAssemblyTypes(typeof(Controller).Assembly)
  .AssignableTo<Controller>()
  .InstancePerLifetimeScope()
  .PropertiesAutowired(propSelector);

但它对我不起作用,所以我使用了从官方网站获取的以下代码片段。

var dataAccess = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(dataAccess)
               .Where(t => t.Name.EndsWith("Controller"))
               .InstancePerLifetimeScope()
               .PropertiesAutowired();

https://autofaccn.readthedocs.io/en/latest/register/scanning.html