C# Autofac不解析控制器操作参数

C# Autofac不解析控制器操作参数,c#,asp.net-mvc,autofac,C#,Asp.net Mvc,Autofac,我有一个名为LanguageBase的抽象类 我还拥有一个名为Language的派生类(不必担心我为什么这样做——这有一个有效的用例,但不在本文讨论的范围之内) 在我的ASP.NETMVC应用程序中,我有一个控制器,其中一些操作方法将LanguageBase作为参数。在运行时,Autofac必须将其解析为语言 在Global.asax中,我使用以下方法注册类型并创建容器: private void RegisterTypes() { var builder = new

我有一个名为LanguageBase的抽象类

我还拥有一个名为Language的派生类(不必担心我为什么这样做——这有一个有效的用例,但不在本文讨论的范围之内)

在我的ASP.NETMVC应用程序中,我有一个控制器,其中一些操作方法将LanguageBase作为参数。在运行时,Autofac必须将其解析为语言

在Global.asax中,我使用以下方法注册类型并创建容器:

 private void RegisterTypes()
    {
        var builder = new ContainerBuilder();

        //http://autofac.readthedocs.org/en/latest/integration/mvc.html
        builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();

        builder.RegisterType<Language>().As<LanguageBase>();

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

    }

您的问题与Autofac无关。MVC框架负责根据请求中的数据为action方法创建参数

尽管您可以创建自定义模型绑定器(通过接口)来解决问题,但我建议您不要使用包含行为的操作参数

相反,创建一个只包含数据的简单模型(例如,
语言
),并将其用作操作参数。还有另一个服务(例如,
ILanguageService
),其中包含您可能希望使用DI改变的行为。这样的服务将被注入控制器的构造函数中



看一看。在我看来,动作方法位于应用程序的边界。所以你的动作参数不应该是面向对象的,也就是说,它们不应该包含行为。它们应该是简单的数据对象。然后,您可以使用另一个服务将简单的数据对象转换为某个面向对象的对象(包含行为)。这样的服务将通过构造函数注入(因此Autofac可以处理它).

您能在控制器中显示相关代码吗?@YacoubMassad controller code已添加…为什么要将
LanguageBase
注入
Edit
方法而不是构造函数?@YacoubMassad模型绑定需要针对操作方法的语言参数进行。@CraftBeerHipsterDude查看操作注入:看起来像是用
[DataServices]
装饰参数,允许操作注入;我只知道MVCT中的构造函数注入支持这种方法的问题是它仍然需要将轻量级/dto/viewmodel语言对象映射到抽象类LanguageBase的实例化,从而强制使用servicelocator反模式来创建这样的实例。我从控制器方法调用的服务是黑盒,这意味着我无法从这些服务内部处理此映射。为什么需要此ViewModel从
LanguageBase
继承?在这种情况下,为什么需要使用服务定位器?您能详细说明一下吗?viewmodel不必从LanguageBase继承,但由于我的数据访问组件将LanguageBase对象作为参数,因此我确实需要创建LanguageBase的实例以传递到我的数据访问组件中。因此,我必须创建一个LanguageBase派生实例(使用servicelocator)并将viewmodel对象的值映射到该实例。将一些
IConverter
服务注入控制器的构造函数,该服务可以将您的视图模型转换为
LanguageBase
的派生类。我想这就是我最终要做的。然而,它仍然感觉好像动作方法注入是Autofac MVC库应该支持的东西。
using System;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using Visia.MasterData.Banking.DAL;
using Visia.PartyRoles.Core.Banking.IDataServices;
using Visia.PartyRoles.Generic.IDomain;

namespace Visia.CrediScan.UI.Views
{
    public class LanguagesController : Controller
    {
        private readonly QueryBase _query;
        private readonly CommandBase _command;

        public LanguagesController(QueryBase query, CommandBase command)
        {
            if (query == null) throw new ArgumentNullException(nameof(query));
            if (command == null) throw new ArgumentNullException(nameof(command));
            _query = query;
            _command = command;
        }

        // GET: /Languages/Edit/5
        public ActionResult Edit(long? id, long CountryId)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var language = _query.GetLanguage((long)id);
            if (language == null)
            {
                return HttpNotFound();
            }
            ViewBag.CountryId = CountryId;
            return View(language);
        }

        // POST: /Languages/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(LanguageBase language, long CountryId)
        {
            if (ModelState.IsValid)
            {
                language.CountryId = CountryId.ToString();
                _command.Update(language);
                return RedirectToAction("Index", new { CountryId = CountryId });
            }
            return View(language);
        }
    }
}