【问题标题】:How to inject services into view/viewmodel using Ninject in MVC3?如何在 MVC3 中使用 Ninject 将服务注入视图/视图模型?
【发布时间】:2011-10-23 07:30:03
【问题描述】:

我将 MVC3 与 Ninject 一起使用,我的控制器中的依赖关系已毫无问题地解决。我几乎没有像本地化、格式提供程序这样的服务,我希望将它们注入到视图模型或 Razor 视图中。现在我手动将它们注入到我的视图模型中,

  1. 如何实现自动化?
  2. 我可以向 Razor 视图注入一些服务吗?
  3. 如何在 MVC 中使用 Ninject 设置服务定位器?

对于其他人: 似乎 Service Locator 是个坏主意,因为 Ninjects Bootstrapper.Kernel 已过时,而 Service Locator 是一种反模式。看看这篇文章http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

_

public class HomeController : Controller
{
    //This gets injected correctly
    [Inject]
    public ILocalizationService LocalizationService { get; set; }

    //This gets injected correctly
    [Inject]
    public MyModel Model { get; set; }

    public ActionResult Index()
    {
        var modelResult = Model.GetStuff();
        //Here I am manully injecting my services to my View Model,
        //I would like Ninject to inject services into my view model.
        var viewModelResult = IndexViewModel.Covert(LocalizationService, modelResult);
        return View(viewModelResult);
    }


    public ActionResult About()
    {
        return View();
    }
}

【问题讨论】:

    标签: .net asp.net-mvc-3 ninject service-locator


    【解决方案1】:

    将格式提供程序注入控制器,然后在创建时将它们设置在 ViewModel 上。

    【讨论】:

    • 我无法从代码示例中看出,但在您的问题中,您明确表示要注入视图模型。我认为这是一个糟糕的计划。如果您的控制器中有格式提供程序,那么您应该按照 StriplingWarrior 的建议在模型上简单地设置字符串属性。你应该是金色的。
    • 我在这里有两种选择来实现这些转换1. 纯粹的方法[至少在我看来] 创建将模型作为输入并转换为 ViewModel 的转换器[类]具有格式化/本地化的值,视图仅显示它。这就是我现在正在做的,ViewModel 为 View 做两件事 DTO 和从模型 2 的转换。 在控制器中进行这些转换,我认为这种方法有点难看,因为控制器做了很多事情并使我的 TDD 更难.
    • 所以问题是,如何自动将服务注入这些转换器?我可以公开只读 Ninject Kernel 来解析这些服务吗?
    • 我不太了解 Ninject 的具体情况。一般来说,我认为您不希望您的 ViewModel 做任何事情,它应该是一个简单的属性包。您可能需要一些其他机制来进行转换。我不确定你为什么认为在控制器中进行转换是丑陋的。这是设置模型属性的合乎逻辑的地方。只需确保转换逻辑是控制器正在使用的服务。
    • >>我不知道你为什么认为在控制器中进行转换是丑陋的。 我的转换逻辑很复杂,将它放在控制器中会使我的单元测试生活变得艰难.所以我不得不把这个逻辑移到一个单独的地方。如果我想成为一个纯粹主义者,我可以创建单独的转换器来了解模型和视图模型。为简单起见,我将这些转换保留在 ViewModel 中。
    【解决方案2】:

    如果您使用的是 Ninject 的 MVC 3 插件,那么创建所有可用的挂钩非常好。我认为支持 Razor 视图:如果您创建一个扩展典型 View 类的类并将注入的依赖项添加到该类,我认为 Ninject 将能够注入这些项目以便它们可用在视图中给你。

    就我的观点而言,我更喜欢使用自定义的基于 HtmlHelper 的扩展方法,最终间接使用基于单例的服务定位器模式来访问适当的依赖项。如果您发现说 Html.MyMethod(...)Url.MyMethod(...) 或类似的内容没有意义,那么您尝试包含的项目很可能不属于您的视图。

    同样,模型对象通常应该只是 POCO,与它们关联的逻辑数量最少。用服务填充它们听起来违反了 MVC 模型。正如 Jason 指出的那样,您可以从控制器的代码中设置模型上的格式提供程序。但是,我想说使用格式提供程序来生成您需要的字符串并将those 放在模型上会更好。

    在 Jason 的帖子中回复 cmets

    方法 1 听起来是个好主意,因为听起来您的控制器变得越来越复杂,这是将关注点分成不同类的好地方。如果您将Converter 本身注入到您的控制器中,而不是将其用作静态类,则在 Ninject 创建控制器时将自动注入其依赖项。

    public class HomeController : Controller
    {
        [Inject]
        public ViewModelConverter Converter { get; set; }
    
        [Inject]
        public MyModel Model { get; set; }
    
        public ActionResult Index()
        {
            var modelResult = Model.GetStuff();
            var viewModelResult = Converter.MakeViewModel(modelResult);
            return View(viewModelResult);
        }
    
    
        public ActionResult About()
        {
            return View();
        }
    }
    
    public class ViewModelConverter
    {
        [Inject]
        public ILocalizationService LocalizationService { get; set; }
        
        public ViewModel MakeViewModel(MyModel model)
        {
            // You should be able to use LocalizationService here
        }
    }
    

    我坚持使用基于属性的注入,尽管我个人更喜欢使用构造函数注入。

    【讨论】:

    • 就像突出显示句子一样,“您尝试包含的项目很可能不属于您的视图”。控制器的重点是进行格式化和处理,并设置所有 ViewModel,以便视图可以按原样使用它。
    • @StriplingWarrior 查看我对 Jason 的回答。
    • @iraSenthil:在我的回答中查看我的回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 2020-06-20
    • 2023-01-09
    相关资源
    最近更新 更多