3

In web forms I would use constructor dependency injection in my models like the below:

[SitecoreType(AutoMap = true)]
public class Article
{
    private readonly ICommonService _commonService;

    public Article(ICommonService commonService)
    {
        _commonService = commonService;
    }

    [SitecoreId]
    private Guid Id { get; set; }

    public string Title { get; set; }

    [SitecoreIgnore]
    public string GetTestString
    {
        get { return _commonService.GetTestString(); }
    }
}

The idea here is to move the logic into services and keep loosely coupled with DI. So Glass provides raw Sitecore data then the services help manipulate that data or pull in extra data to complete the model.

Is it possible to have a view rendering with a reference to the model which resolves the DI and the model is ready to use?: @inherits Glass.Mapper.Sc.Web.Mvc.GlassView

Currently when i attempt this I get No parameterless constructor defined for this object

I can get the above working by using a controller and passing the dependency into the model via the controller.

Is it possible to have this work in a simple view rendering to cut out the creation of a controller view for models that requires logic in addition to simple Glass ORM data?

Currently posted in Glass Mapper Google Group: https://groups.google.com/forum/#!topic/glasssitecoremapper/BJnfQGXR7S8

skaffman
  • 398,947
  • 96
  • 818
  • 769
Jason Horne
  • 595
  • 3
  • 12

2 Answers2

3

You can use the ObjectConstruction pipeline for this. You need to add a new class which implements IObjectConstructionTask and resolves your class using your IoC container, i.e.:

public class IoCResolvingTask : IObjectConstructionTask
{
    public virtual void Execute(ObjectConstructionArgs args)
    {
        // check that no other task has created an object and that this is a dynamic object
        if (args.Result != null || args.Configuration.Type.IsAssignableFrom(typeof(IDynamicMetaObjectProvider))) return;

        // create instance using your container
        var obj = Container.Resolve(args.Configuration.Type);

        // map properties from item to model
        args.Configuration.MapPropertiesToObject(obj, args.Service, args.AbstractTypeCreationContext);

        // set the new object as the returned result
        args.Result = obj;
    }
}

Then you neeed to register your task to Glass:

public static void CastleConfig(IWindsorContainer container){
    var config = new Config();

    container.Register(Component.For<IObjectConstructionTask>().ImplementedBy<IoCResolvingTask>().LifestylePerWebRequest());

    container.Install(new SitecoreInstaller(config));
}
Kevin Brechbühl
  • 4,717
  • 3
  • 24
  • 47
  • I added this code to your first snippet as I had no reference to the Container. : private readonly IWindsorContainer _container; public IoCResolvingTask(IWindsorContainer container) { _container = container; } Should that be right? I then added the final code also but I still get the same error – Jason Horne Feb 22 '15 at 05:38
  • DId you also pass the container then to the castle registration, like this: `container.Register(Component.For().ImplementedBy().DependsOn(Dependency.OnValue(container).LifestylePerWebRequest());`? With your code you must pass the container as a constructor argument. I don't know castle that well and don't know if the snippet in this comment works, haven't tested it. – Kevin Brechbühl Feb 22 '15 at 09:31
  • Hi, I hadn't registered like that, however I have updated now but still get the same error. – Jason Horne Feb 22 '15 at 22:10
  • Is your IConmonService registered in the container you pass in the constructor? Is it registered in the same container as Glass? Or is it another franework/container? What says the debugger? Is the construction task being called? Here is a tutorial from Glass on how to use it: http://www.glass.lu/en/Blog/MixingInIoc.aspx – Kevin Brechbühl Feb 23 '15 at 06:38
  • Thanks for your help Kevin. – Jason Horne May 29 '15 at 08:26
0

Is it possible to have a view rendering with a reference to the model which resolves the DI and the model is ready to use?: @inherits Glass.Mapper.Sc.Web.Mvc.GlassView

The answer is yes it can be done.

Within Models DI is resolved automatically. From controllers and other areas I resorted to using the service locator pattern: https://msdn.microsoft.com/en-us/library/ff648968.aspx

The issue I was having was with setup and configuration. Here is the code I have implemented to get this working successfully.

glassMapperCustom.cs

 public static void CastleConfig(IWindsorContainer container)
    {
        var config = new Config { UseWindsorContructor = true };

        container.Install(new SitecoreInstaller(config));
        container.Install(new ServiceInstaller());
    }  

Service Installer code

public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<ICustomService>().ImplementedBy<CustomService>().LifestyleTransient(),            
            Component.For<SitecoreController>().ImplementedBy<SitecoreController>().LifestylePerWebRequest()
                .DependsOn(new { databaseName = Sitecore.Context.Database }));

        // Set up the servicelocator. We can use this in the code to get instances of services.
        ServiceLocator.SetLocatorProvider(() =>
                    new WindsorServiceLocator(container));
    }

Global.asax

   public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute(
            "SiteName", // Route name 
            "SiteName/{controller}/{action}/{id}", // URL with parameters 
            new { controller = "Home", action = "Index", id = System.Web.Mvc.UrlParameter.Optional }); // Parameter defaults 
    }

    /// <summary>
    /// Registers the global filters.
    /// </summary>
    /// <param name="filters">Global filter collection.</param>
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

    /// <summary>
    /// Will be called when the application first starts.
    /// </summary>
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }
Jason Horne
  • 595
  • 3
  • 12