使用统一容器将对象注入控制器的构造函数
Inject object to the constructor of controller using unity container
我找不到任何类似的问题,所以我写这篇文章 post。有一个带有私有字段 IBaseClass 的示例控制器。示例代码如下所示:
public class TmpController : Controller
{
private IBaseClass _baseClass;
public TmpController()
{
_baseClass = new BaseClass(this);
}
}
public interface IBaseClass
{
//...
}
public class BaseClass : IBaseClass
{
protected TmpController TmpController;
public BaseClass(TmpController tmpController)
{
TmpController = tmpController;
}
//IBaseClass implementation
}
我的问题是;如何使用 Unity 框架将 BaseClass 对象注入到 TmpController 的构造函数中?
我想让我的控制器 "slimmer"。我想将有关验证和准备我的控件(如 comboBox 等)的数据源的逻辑放到不同的 class。在那个非常具体的案例中,我尝试在我的 .Web 项目中制作某种 SOC,这将使我的控制器更易于阅读和维护。我在每个视图中使用一个控制器的方法,但我遇到了非常复杂的情况。目前我有超过 3000 行代码的控制器并且很难维护所以我想用它做点什么。
是的,我正在使用服务和存储库,但问题是关于 ViewModel 的验证、将 ViewModel 对象映射到 DTO 和向后映射、准备给定组件的数据源等。
@Razem,你从我的评论中猜到的是正确的。并且您描述的负点也是有效的。
你问的"Service depending on the controller"当然可以实现,但那将是一个糟糕的设计。
目前 BaseClass
仅依赖于 TempController
。当您在其他一些控制器中也需要 BaseClass
时,您将如何处理这种情况?代码将开始中断,您最终将向 BaseClass
添加新的依赖项。
此外,根据设计建议,顶层应依赖于底层,反之亦然。
话虽如此,您仍然可以通过使控制器依赖于 IBaseClass
来实现您正在寻找的功能。
我不确定您需要访问内部控制器的具体原因BaseClass
。我在创建以下建议时做出了某些假设。其中一个假设是 BaseClass
、IBaseClass
和 Controller
类 是同一程序集的一部分。
//Have a BaseController Class with the properties and/or method which you will be using in the `BaseClass` class and make them virtual so that derived controller classes can override them to have specific implementation.
public class BaseController : Controller
{
public virtual string ControllerMethod()
{
return "Controller Method from Base Controller";
}
public virtual string RandomValue
{
get
{
return "Random value from Base Controller";
}
}
}
在 IBaseClass
中创建一个方法,它将为其设置控制器。
public interface IBaseClass
{
void SetController(BaseController controller);
void Method1();
}
public class BaseClass : IBaseClass
{
private BaseController controller;
public void SetController(BaseController controller)
{
this.controller = controller;
}
public void Method1()
{
var str = this.controller.RandomValue;
}
}
并从 BaseController
派生 TempController
并使其依赖于 IBaseClass
。并在 TempController
的构造函数中通过传递 this
参数来调用 IBaseClass
的 SetController
方法。您也可以在此处覆盖 BaseController
的 method/properties。
在此之后,您可以调用 IBaseClass
的任何方法,而无需将控制器实例传递给它。
public class TempController : BaseController
{
private IBaseClass baseClass;
public HomeController(IBaseClass productService)
{
this.baseClass = productService;
this.baseClass.SetController(this);
}
public override string RandomValue
{
get
{
return "Random value from Derived Class.";
}
}
public ActionResult Index()
{
this.baseClass.Method1();
ViewBag.Title = "Home Page";
return View();
}
}
在您的 Web 项目中安装 nuget 包 Unit.Mvc。打开位于 App_Start 文件夹下的文件 Unity.Config
并更改方法 RegisterTypes
如下。
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IBaseClass, BaseClass>(new PerRequestLifetimeManager());
}
我相信我不需要解释这是如何工作的。
P.S。 : 您需要确保在控制器构造函数中调用 IBaseClass.SetController
方法以避免在 BaseClass
中使用控制器时出现 NullReferenceException。这是实现良好且可维护的设计所需的很小的开销。
我找不到任何类似的问题,所以我写这篇文章 post。有一个带有私有字段 IBaseClass 的示例控制器。示例代码如下所示:
public class TmpController : Controller
{
private IBaseClass _baseClass;
public TmpController()
{
_baseClass = new BaseClass(this);
}
}
public interface IBaseClass
{
//...
}
public class BaseClass : IBaseClass
{
protected TmpController TmpController;
public BaseClass(TmpController tmpController)
{
TmpController = tmpController;
}
//IBaseClass implementation
}
我的问题是;如何使用 Unity 框架将 BaseClass 对象注入到 TmpController 的构造函数中? 我想让我的控制器 "slimmer"。我想将有关验证和准备我的控件(如 comboBox 等)的数据源的逻辑放到不同的 class。在那个非常具体的案例中,我尝试在我的 .Web 项目中制作某种 SOC,这将使我的控制器更易于阅读和维护。我在每个视图中使用一个控制器的方法,但我遇到了非常复杂的情况。目前我有超过 3000 行代码的控制器并且很难维护所以我想用它做点什么。 是的,我正在使用服务和存储库,但问题是关于 ViewModel 的验证、将 ViewModel 对象映射到 DTO 和向后映射、准备给定组件的数据源等。
@Razem,你从我的评论中猜到的是正确的。并且您描述的负点也是有效的。
你问的"Service depending on the controller"当然可以实现,但那将是一个糟糕的设计。
目前 BaseClass
仅依赖于 TempController
。当您在其他一些控制器中也需要 BaseClass
时,您将如何处理这种情况?代码将开始中断,您最终将向 BaseClass
添加新的依赖项。
此外,根据设计建议,顶层应依赖于底层,反之亦然。
话虽如此,您仍然可以通过使控制器依赖于 IBaseClass
来实现您正在寻找的功能。
我不确定您需要访问内部控制器的具体原因BaseClass
。我在创建以下建议时做出了某些假设。其中一个假设是 BaseClass
、IBaseClass
和 Controller
类 是同一程序集的一部分。
//Have a BaseController Class with the properties and/or method which you will be using in the `BaseClass` class and make them virtual so that derived controller classes can override them to have specific implementation.
public class BaseController : Controller
{
public virtual string ControllerMethod()
{
return "Controller Method from Base Controller";
}
public virtual string RandomValue
{
get
{
return "Random value from Base Controller";
}
}
}
在 IBaseClass
中创建一个方法,它将为其设置控制器。
public interface IBaseClass
{
void SetController(BaseController controller);
void Method1();
}
public class BaseClass : IBaseClass
{
private BaseController controller;
public void SetController(BaseController controller)
{
this.controller = controller;
}
public void Method1()
{
var str = this.controller.RandomValue;
}
}
并从 BaseController
派生 TempController
并使其依赖于 IBaseClass
。并在 TempController
的构造函数中通过传递 this
参数来调用 IBaseClass
的 SetController
方法。您也可以在此处覆盖 BaseController
的 method/properties。
在此之后,您可以调用 IBaseClass
的任何方法,而无需将控制器实例传递给它。
public class TempController : BaseController
{
private IBaseClass baseClass;
public HomeController(IBaseClass productService)
{
this.baseClass = productService;
this.baseClass.SetController(this);
}
public override string RandomValue
{
get
{
return "Random value from Derived Class.";
}
}
public ActionResult Index()
{
this.baseClass.Method1();
ViewBag.Title = "Home Page";
return View();
}
}
在您的 Web 项目中安装 nuget 包 Unit.Mvc。打开位于 App_Start 文件夹下的文件 Unity.Config
并更改方法 RegisterTypes
如下。
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IBaseClass, BaseClass>(new PerRequestLifetimeManager());
}
我相信我不需要解释这是如何工作的。
P.S。 : 您需要确保在控制器构造函数中调用 IBaseClass.SetController
方法以避免在 BaseClass
中使用控制器时出现 NullReferenceException。这是实现良好且可维护的设计所需的很小的开销。