FormCollection to Interface?

Nov 19, 2009 at 6:53 PM

Can this map from System.Web.Mvc.FormCollection to an Interface?

 

In MVC if I have an action:

 

[HttpPost]
        public ActionResult Create(FormCollection formCollection)
{
var customer=EmitMapper.Map<IAmACustomer>(formCollection);
//Etc...
}


public interface IAmACustomer
{
public FirstName {get;set}
//etc....
}

Is this possible? I've been trying to find a way to get AutoMapper to do this for a few days now.

 

Coordinator
Nov 19, 2009 at 10:23 PM
Edited Nov 19, 2009 at 10:29 PM

EmitMapper can map FormCollection to an object or create an instance of an existing Type. But currently EmitMapper cannot build abstract implementation of an interface in run-time. So, you have to have customer type implementation:

public class AmACustomer
{
public FirstName {get;set}
//etc....
}

In order to setup mapping from FormCollection to an object you have to use custom mapping configurator like this:

 

public class FormCollectionMapConfig:IMappingConfigurator
{
    public IMappingOperation[] GetMappingOperations(Type from, Type to)
    {
        var members = ReflectionUtils.GetPublicFieldsAndProperties(to);
        return members
            .Select(
                m =>
                new DestWriteOperation()
                {
                    Destination = new MemberDescriptor(m),
                    Getter =
                        (form, valueProviderObj) =>
                        {
                            var valueProvider = valueProviderObj as IDictionary<string, ValueProviderResult>;
                            if (valueProvider == null)
                            {
                                valueProvider = ((FormCollection)form).ToValueProvider();
                            }

                            ValueProviderResult res;
                            if(valueProvider.TryGetValue(m.Name, out res))
                            {
                                return ValueToWrite.ReturnValue(res.ConvertTo(ReflectionUtils.GetMemberType(m)));
                            }
                            else
                            {
                                return ValueToWrite.Skip();
                            }
                        }
                }
            )
            .ToArray();
    }

    public TargetConstructor GetTargetConstructor(Type targetType)
    {
        return null;
    }

    public string GetConfigurationName()
    {
        return null;
    }
}

 

Using is showed below:

 

public class EmitMapperTestController : Controller
    {
        static ObjectsMapper<FormCollection, CustomerModel> _customerMapper =
            ObjectsMapperManager.DefaultInstance.GetMapper<FormCollection, CustomerModel>(
                    new FormCollectionMapConfig()
                );

        public ActionResult Index(FormCollection form)
        {
            CustomerModel model;
            if (form != null && form.Count > 0)
            {
                model = _customerMapper.MapUsingState(form, form.ToValueProvider());
            }
            else
            {
                model = new CustomerModel();
            }
            return View(model);
        }
    }

 

Apr 27, 2010 at 9:27 AM

Is this the correct design ?

The correct best practice (imho) should be:

[HttpPost]
public ActionResult Create(CustomerModel model)
{
// Convert CustomerModel (view only) to real Customer (database),
// maybe this can easily done using EmitMapper?
var customer = ...

}


To make it possible that MVC understands the CustomerModel correctly, name the values on the View.aspx page correctly.