Blog Archive

Wednesday, July 4, 2012

IoC inject data into DropDownListFor

  DropDownListFor(m=>m.Name, ViewData["TheList"] requires repeatedly build ViewData. AutoFac IoCContainer Dependency Injection Could be used to avoid duplicating these code:

(1) We need to build Referenc List Types so we can resolve a Generic Type for IoC (i.e we cannot use Enum)
(2) Dependency Inject will inject a Repository IReferenceListRepository
(3) The generic Type SelectionList  must be able to render a list of SelectItem to feed into DropDownListFor base(LinqExpression, IEnumeralb)
(4) DropDownListFor Extension can now  build a generic type using type input param

    #region Reference List types

    public class USStatesRefList : ReferenceListType { }
    public class ApppealStatusesRefList : ReferenceListType { }
    public class EscalationToRefList : ReferenceListType { }

    public class ReferenceListType
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public string ShortName { get; set; }
    }

    #endregion

  #region Ref Data Repository

    public interface IReferenceListRepository
    {
        IEnumerable<T> All<T>();
    }

    public class ReferenceListRepository : IReferenceListRepository
    {
        public IEnumerable<T> All()
        {
            // TODO; Build List from Database or RavenDB
            if (typeof(T)==typeof(USStatesRefList))
            {
              List<USStatesRefList> list= new List<USStatesRefList>() { new USStatesRefList() { Id=1, ShortName="MA", Description="MASS"}, new USStatesRefList() {Id=2, ShortName="NY",Description="Empire State"}};
              return (IEnumerable <T> ) list.AsEnumerable();
            }
            return default(IEnumerable<T>);
        }
    }
    #endregion

  #region Selection List -- can fill dropdown

    public class SelectionList<T> : IReferenceListRenderer where T : ReferenceListType
    {
       
        IEnumerable<T> _All { get;  set; }

       // Repository get injected here
        public SelectionList(IReferenceListRepository repository)
        { 
           _All = repository.All<T>();
        }

        public List<SelectListItem> RenderList(IConvertible value)
        {
            return (from p in _All
                   select
                       new SelectListItem
                       {
                           Value = null, // p.Id.ToString(),  DropDownList mal function if Value get set
                           Text =p.ShortName,// string.Format("{0} ({1})", p.Description, p.Id),
                           Selected =ValueEqual(p,value)
                       }).ToList();
        }

        public bool ValueEqual(ReferenceListType p, IConvertible value)
        {
            // For selection List, shortname matching ToString() is the only valid case
            return p.ShortName == Convert.ToString(value);
        }
    }

    public interface IReferenceListRenderer
    {
        List<SelectListItem> RenderList(IConvertible value);
    }

    #endregion


   #region Drop Down List  without using ViewData

    public static class DropDownListExtensions
    {
        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> h,
                                                                       Expression<Func<TModel, TProperty>> expression,
                                                                       Type listType) where TProperty : IConvertible
        {

            var property = expression.Compile()(h.ViewData.Model);

            var SelectionListT = typeof(SelectionList<>).MakeGenericType(listType);
            var listR = DependencyResolver.Current.GetService(SelectionListT) as IReferenceListRenderer;
           List<SelectListItem> list = listR.RenderList(property);
            return h.DropDownListFor(expression,list );
        }
    }

    #endregion

@Html.DropDownListFor(m => m.Name, typeof(USStatesRefList));

Boiler Template code to hook up IoC

 protected void Application_Start()
        {
      var builder = new ContainerBuilder();
            builder.RegisterControllers(typeof(MvcApplication).Assembly);//Assembly.GetExecutingAssembly());
            builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
            builder.RegisterModule(new ApplicationModule());
            
            var container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

   public class ApplicationModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
           // builder.RegisterInstance<ILog>(LogManager.GetLogger("TheInstance"));
            builder.RegisterType<ReferenceListRepository>().As<IReferenceListRepository>().InstancePerLifetimeScope();
            builder.RegisterGeneric(typeof(SelectionList<>)).SingleInstance();
           
        }


No comments: