0

I have setup Castle Windsor and WebApi after reading about it in the below 2 posts. Here is my a highlight of my setup:

Reference Posts:

Code Setup:

public static class GlassMapperScCustom
{
    public static void CastleConfig(IWindsorContainer container)
    {
        container.AddFacility<TypedFactoryFacility>();

        var config = new Config
        {
            UseWindsorContructor = true
        };

        //MVC
        container.Register(Component.For<SitecoreController>().LifestyleTransient());
        container.Register(Types.FromThisAssembly().BasedOn<Controller>().LifestyleTransient());
        DependencyResolver.SetResolver(new WindsorMvcDependencyResolver(container));
        ControllerBuilder.Current.SetControllerFactory(new WindsorMvcControllerFactory(container.Kernel));

        //WebApiInstaller
        container.Register(Types.FromThisAssembly().BasedOn<ApiController>().LifestyleTransient());
        var resolver = new WindsorResolver(container); //Shown Below
        GlobalConfiguration.Configuration.DependencyResolver = resolver;
        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorWebApiControllerActivator(resolver));
    }
}
public class WindsorMvcDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer _container;

    public WindsorMvcDependencyResolver(IWindsorContainer container)
    {
        if (container == null) throw new ArgumentNullException("container");
        _container = container;
    }

    public object GetService(Type serviceType)
    {
        return _container.Kernel.HasComponent(serviceType) ? _container.Resolve(serviceType) : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _container.ResolveAll(serviceType).Cast<object>().ToArray();
    }
}

public class WindsorMvcControllerFactory : DefaultControllerFactory
{
    private readonly IKernel _kernel;

    public WindsorMvcControllerFactory(IKernel kernel)
    {
        this._kernel = kernel;
    }

    public override void ReleaseController(IController controller)
    {
        _kernel.ReleaseComponent(controller);
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", 
                requestContext.HttpContext.Request.Path));
        }
        return (IController)_kernel.Resolve(controllerType);
    }
}

internal class WindsorResolver : IDependencyResolver, IDependencyScope, IDisposable
{
    private readonly IWindsorContainer _container;

    public WindsorResolver(IWindsorContainer container)
    {
        this._container = container;
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(this._container);
    }

    public void Dispose()
    {
        this._container.Dispose();
    }

    public object GetService(Type serviceType)
    {
        if (!this._container.Kernel.HasComponent(serviceType))
            return (object)null;
        else
            return this._container.Resolve(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        if (!this._container.Kernel.HasComponent(serviceType))
            return (IEnumerable<object>)new object[0];
        else
            return Enumerable.Cast<object>((IEnumerable)this._container.ResolveAll(serviceType));
    }
}

public class WindsorWebApiControllerActivator : IHttpControllerActivator
{
    private readonly IDependencyResolver _container;

    public WindsorWebApiControllerActivator(IDependencyResolver container)
    {
        _container = container;
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        var scope = _container.BeginScope();
        var controller = (IHttpController)scope.GetService(controllerType);
        request.RegisterForDispose(scope);
        return controller;
    }
}

//WebApiConfig.cs
public static class WebApiConfig
{
    public static void Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
    }

    public static void Register(HttpConfiguration config)
    {
        // initialize and map all attribute routed Web API controllers (note: this does not enable MVC attribute routing)
        config.MapHttpAttributeRoutes();
        config.EnsureInitialized();

        //config.Routes.MapHttpRoute(
        //    name: "DefaultApi",
        //    routeTemplate: "api/{controller}/{id}",
        //    defaults: new {id = RouteParameter.Optional});


        // force JSON responses only (no XML)
        config.Formatters.Clear();
        config.Formatters.Add(new JsonMediaTypeFormatter());
    }
}

//Global.asax.cs
public class MvcApplication : Sitecore.Web.Application
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }
}

If I add a test ApiController and try to go to '/api/Test' it gives me a 404 everytime. I used RouteDebugger to view whats wrong and I get the below error everytime:

public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }


    public string Get(int id)
    {
        return "value";
    }

I am not sure where "api/sitecore" is coming from. I followed the instructions on [WebApi2 Attribute Routing with Sitecore][1] post as well but unable to get it working. Can someone point me to what I am doing wrong?

Community
  • 1
  • 1
Chitrang
  • 1
  • 4

2 Answers2

0

Sitecore is using /api/ as its default route URL.
Rename your controller to something else than ApiController or change Sitecore's default route in the Global.asax and web.config

Ruud van Falier
  • 8,765
  • 5
  • 30
  • 59
  • Hey @Ruud van Falier, thanks for your reply. My controller is named TestController which inherits ApiController. I followed this link's http://kamsar.net/index.php/2014/05/using-web-api-2-attribute-routing-with-sitecore/ instructions. But it doesn't work for me. Should I be adding my custom route in Global.asax.cs as well which kind of defeats the purpose of Attribute Routing? – Chitrang Oct 13 '14 at 12:33
  • I notified Kam about your question, maybe he can help. – Ruud van Falier Oct 13 '14 at 18:31
  • Hey @Ruud van Falier, I was able to get WebApi by intercepting the pipeline as mentioned in this link [SitecoreWebApi](http://patrickdelancy.com/2013/08/sitecore-webapi-living-harmony/). But now, it seems that the regular sitecore route is not working. I added a SitecoreController and tried to invoke it with "api/sitecore/{controller}/{action}/{id}" and it gives me a 404. – Chitrang Oct 15 '14 at 15:30
0

From a quick glance it looks like there are no routes registered. The only route in WebApiConfig is commented out.

  • Hey @Vasiliy Fomichev, I have added "config.MapHttpAttributeRoutes();" which resolves the attribute routing for WebApi. Nonetheless, I was able to get it working by following the steps in this link [SitecoreWebApi](http://patrickdelancy.com/2013/08/sitecore-webapi-living-harmony/#.VD6RwRaOpsk). – Chitrang Oct 15 '14 at 15:32