Question

I have an interface which has a property that is a list of an another interface and a class which implemented that interface, i registered it for Autofac, but my problem is Autofac not bind data to my class, i wrote my code below :

My Interfaces :

public interface IDetail
{
    int Id { get; set; }

    string Name { get; set; }
}

public interface IMaster
{
    int Id { get; set; }

    DateTime Description { get; set; }

    List<IDetail> Details { get; set; }
}

My Classes :

public class Detail : IDetail
{
    public int Id { get; set; }

    public string Name { get; set; }
}

public class Master : IMaster
{
    public int Id { get; set; }

    public DateTime Description { get; set; }

    public List<IDetail> Details { get; set; }
}

My Controller :

public class HomeController : Controller
    {
        IMaster _t;

        [HttpPost]
        public ActionResult Create(IMaster t)
        {
            _t = t;
        }


    }

My Autofac Registeration :

    public class DependencyConfigure
        {
//Initializing
            public static void Initialize()
            {
                RegisterServices();
            }

//Registering
            private static void RegisterServices()
            {

                ContainerBuilder builder = new ContainerBuilder();

                builder.RegisterAssemblyTypes(
                    typeof(MvcApplication).Assembly
                    ).PropertiesAutowired();            

                builder.RegisterType<ExtensibleActionInvoker>()
                .As<IActionInvoker>()
                .WithParameter("injectActionMethodParameters", true);
                        builder.RegisterControllers(Assembly.GetExecutingAssembly())
                            .InjectActionInvoker();

                builder.RegisterType(typeof(Master)).As(typeof(IMaster));

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

        }

and the view is here :

@model WebApplication1.Models.Master

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

        <div class="form-group">
            @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Description)
                @Html.ValidationMessageFor(model => model.Description)
            </div>
        </div>

        <div>
            @Html.Label("Details.Name", new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.Editor("Details[0].Name")                
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

In other word, when I submit, data not bind to Master.Details...

Was it helpful?

Solution 2

the right answer is here, for these reason you need to write a custom binder to mvc before bind your data to your viewmodel, create an instance of viewmodel and then bind data to viewmodel. you can see a sample of binder here ( which has written by my dear freind senior developer @Saeed Hamed)

public class InterfaceModelBinderProvider : 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)
    {
        var item = DependencyResolver.Current.GetService(bindingContext.ModelType);

        bindingContext.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),
            bindingContext.ModelMetadata.ContainerType, () => item, item.GetType(), bindingContext.ModelName);

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

OTHER TIPS

You are doing a few things wrong here.

  1. Autofac has nothing to do with model binding. Autofac is for injecting dependencies into your controller's constructor; the ASP.NET MVC model binder binds HTTP requests to action parameters. They are completely separate concerns. Get rid of your IMaster dependency injection.
  2. MVC cannot bind a form post to an interface because it does not know what concrete type to instantiate. Forget the IMaster interface and use a concrete view model type.
  3. Form posts bind to action parameters, not constructor parameters. You should have an action method that accepts a Master object.

Assuming this is your index action, you should have an action method that looks something like this inside your HomeController:

[HttpPost]
public ActionResult Index(Master model)
{
    ...
}

You may need to make other changes to get where you're going but this should set you off on the right track (right now your code looks very confused).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top