Ehsan Ghorabian
Ehsan Ghorabian

Reputation: 21

autofac not binding data in viewmodel

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...

Upvotes: 0

Views: 1006

Answers (2)

Ehsan Ghorabian
Ehsan Ghorabian

Reputation: 21

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);
    }
}

Upvotes: 1

Ant P
Ant P

Reputation: 25231

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).

Upvotes: 1

Related Questions