对操作方法参数的 Autofac 依赖注入 (ASP MVC3)

发布于 2024-12-11 21:16:18 字数 1205 浏览 0 评论 0原文

我有以下设置

public interface IObject 
{ 
    string Name { get; set;}
}

public class ConcreteObject : IObject 
{
    public string Name { get; set; }
}
public ActionResult Index(IObject myObject)
{        
    return View();
}

我有一个实现 IObject 的具体类,并且我使用依赖项注入将此具体类绑定到接口。

使用 Autofac,我也有以下设置

var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacWebTypesModule());
builder.RegisterSource(new ViewRegistrationSource());
builder.RegisterFilterProvider();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).InjectActionInvoker().PropertiesAutowired();
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>().WithParameter("injectActionMethodParameters", true);
builder.RegisterType<ConcreteObject>().As<IObject>().InstancePerHttpRequest();            
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

当我运行它时,我得到了具体类的一个实例,但通常从查询字符串绑定的任何参数现在都为空。即:Home/Index?Name=test 将绑定一个实例,但不绑定参数Name。有没有办法确保模型绑定在 DI 之后仍然发生?

I have the following setup

public interface IObject 
{ 
    string Name { get; set;}
}

public class ConcreteObject : IObject 
{
    public string Name { get; set; }
}
public ActionResult Index(IObject myObject)
{        
    return View();
}

I have a concrete class which implements IObject, and I am using dependency injection to bind this concrete class to the interface.

Using Autofac, I have the following setup also

var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacWebTypesModule());
builder.RegisterSource(new ViewRegistrationSource());
builder.RegisterFilterProvider();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).InjectActionInvoker().PropertiesAutowired();
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>().WithParameter("injectActionMethodParameters", true);
builder.RegisterType<ConcreteObject>().As<IObject>().InstancePerHttpRequest();            
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

When I run this, I get an instance of the concrete class, but any paramaters that would usually be bound from the querystring are now null. ie: Home/Index?Name=test would bind an instance, but not bind the parameter Name. Is there a way to ensure that modelbinding still happens after DI?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

暗地喜欢 2024-12-18 21:16:18

编辑:我不建议这样做,你永远不应该将接口注入到操作方法中!

好的,我已经解决了这个问题。我设置了一个自定义模型绑定器,当接口存在时我会调用它。

public class YourModelBinderProvider : IModelBinderProvider
{    
    public IModelBinder GetBinder(Type modelType)
    {
        if (modelType.IsInterface)
        {
            return new InterfaceModelBinder();
        }
        return null;
    }
}
public class InterfaceModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        ModelBindingContext context = new ModelBindingContext(bindingContext);
        var item = DependencyResolver.Current.GetService(bindingContext.ModelType);            

        Func<object> modelAccessor = () => item;
        context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),
            bindingContext.ModelMetadata.ContainerType, modelAccessor, item.GetType(), bindingContext.ModelName);

        return base.BindModel(controllerContext, context);
    }
}

然后在我的 global.asax 中我只是有

ModelBinderProviders.BinderProviders.Add(new YourModelBinderProvider());
var builder = new ContainerBuilder();            
builder.RegisterModelBinderProvider();
builder.RegisterType<ConcreteObject>().As<IObject>();    
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Edit: I do no recommend ever doing this, you should never inject interfaces into action methods!.

Ok, I have this solved. I set up a custom model binder which I call when an interface is present.

public class YourModelBinderProvider : IModelBinderProvider
{    
    public IModelBinder GetBinder(Type modelType)
    {
        if (modelType.IsInterface)
        {
            return new InterfaceModelBinder();
        }
        return null;
    }
}
public class InterfaceModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        ModelBindingContext context = new ModelBindingContext(bindingContext);
        var item = DependencyResolver.Current.GetService(bindingContext.ModelType);            

        Func<object> modelAccessor = () => item;
        context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),
            bindingContext.ModelMetadata.ContainerType, modelAccessor, item.GetType(), bindingContext.ModelName);

        return base.BindModel(controllerContext, context);
    }
}

Then in my global.asax I simply have

ModelBinderProviders.BinderProviders.Add(new YourModelBinderProvider());
var builder = new ContainerBuilder();            
builder.RegisterModelBinderProvider();
builder.RegisterType<ConcreteObject>().As<IObject>();    
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
青柠芒果 2024-12-18 21:16:18

尽管我不明白您想使用方法注入实现什么目的,但您可以尝试调用 TryUpdateModel 方法。

Despite that I don't understand what do you want to achieve using method injection, you can try to invoke TryUpdateModel method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文