如何让插件webAPI覆盖现有的webAPI

问题描述:

我有一个Web API控制器,例如EmployeeController,我们使用Autofac注册。现在我们创建另一个具有相同名称和路由的控制器,但具有不同的功能。当我们尝试使用Autofac注册这个新EmployeeController(即插件),我们会得到一个异常喜欢如何让插件webAPI覆盖现有的webAPI

多种类型的发现匹配命名EmployeeController的控制器。

我的目标是成功注入第二个控制器,并用它覆盖第一个控制器的功能。

项目A - >核心项目

namespace Main.API 
{ 
    public class EmployeeController : ApiController 
    { 
     // Some Logic 
    }  
} 

项目B - >插件项目

以后消费者要覆盖与同一控制器名员工控制器

namespace Plugin.API 
{ 
    public class EmployeeController : ApiController 
    { 
     // Some Logic 
    }  
} 

Autofac

// assemblies contains Main.API.dll & Plugin.API.dll 
builder.RegisterApiControllers(assemblies.ToArray()).InstancePerRequest(); 
+0

我认为你会为此工作的自定义注册源。 http://docs.autofac.org/en/latest/advanced/registration-sources.html – Jehof

为了实现你想我会用AOP concept这将使它更容易实现和更强大的东西。

Castle DynamicProxy项目为.net提供AOP概念,可以使用AutofacAutofac.Extras.DynamicProxy2 nuget包。

你将有只有1 EmployeeController在您的主项目

namespace Main.API 
{ 
    public class EmployeeController : ApiController 
    { 
     public virtual String Get(Int32 id) 
     { 
      // Some Logic 
     } 
    }  
} 
在你的插件项目

和各种IInterceptor

namespace Plugin 
{ 
    public class XEmployeeeControllerInterceptor : IInterceptor 
    { 
     public void Intercept(IInvocation invocation) 
     { 
      if(!invocation.Method.Name == nameof(Core.APi.EmployeeController.Get)) 
      { 
       return; 
      } 
      invocation.Proceed(); 

      // alter return value 
      invocation.ReturnValue = invocation.ReturnValue + "-intercepted"; 
     } 
    } 
} 

然后注册这样的事情:

builder.RegisterApiControllers(assemblies.ToArray()) 
     .InstancePerRequest() 
     .EnableClassInterceptors(); 

builder.RegisterAssemblyTypes(assemblies.ToArray()) 
     .As<IInterceptor>(); 

Type Interceptors欲了解更多信息

+0

首先我要感谢Cyril Durand。让我知道,如果有任何可能性,只需在执行RegisterApiControllers时从Main.API dll中排除类型(EmployeeController)?。 在DI注册之前我会检查Main和Plugin之间是否存在相同类型,如果可用,我想从Main排除类型,然后自动从Plugin访问相同类型。 – user1611257

使用下面的代码片段可以覆盖同名的插件控制器。

public class CustomHttpControllerSelector : DefaultHttpControllerSelector 
    { 
     private readonly HttpConfiguration _configuration; 
     private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers; 


    /// <summary> 
    /// custom http controllerselector 
    /// </summary> 
    /// <param name="config"></param> 
    public CustomHttpControllerSelector(HttpConfiguration config) : base(config) 
    { 
     _configuration = config; 
     _controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary); 
    } 

    /// <summary> 
    /// GetControllerMapping 
    /// </summary> 
    /// <returns></returns> 
    public override IDictionary<string, HttpControllerDescriptor> GetControllerMapping() 
    { 
     return _controllers.Value; 
    } 

    private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary() 
    { 
     var controllers = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase); 

     IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver(); 
     IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver(); 
     ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver); 

     foreach (Type t in controllerTypes) 
     { 
      var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length); 

      //Remove Core API Controller and add the Plugin API controller. 
      if (controllers.Keys.Contains(controllerName) && t.Namespace.Contains("Plugin")) 
      { 
       controllers.Remove(controllerName); 
      } 
      if (!controllers.Keys.Contains(controllerName)) 
      { 
       controllers[controllerName] = new HttpControllerDescriptor(_configuration, t.Nam`enter code here`e, t); 
      } 
     } 
     return controllers; 
    } 
}