A newer version of the Ed-Fi ODS / API is available. See the Ed-Fi Technology Version Index for a link to the latest version.

Customizing ODS / API Features

Customizing Startup

To create a custom startup class, inherit from Startup.cs. Override the method EnsureAssembliesLoaded() and add the assemblies that are necessary for the implementation. Note: the EnsureAssmebliesLoaded() method validates that the assemblies are loaded in the app domain, and it does not actually load the specific assembly into the app domain. Add the assembly reference for the Owin startup. 

Below the example is including the enrollment composite, Grand Bend extensions, and sample extensions:

using EdFi.Ods.Api.BulkLoad;
using EdFi.Ods.Common.Extensions;
using EdFi.Ods.Composites.Enrollment;
using EdFi.Ods.Extensions.TPDM;
using EdFi.Ods.Extensions.Sample;
using EdFi.Ods.WebApi.Startup;
using Microsoft.Owin;

[assembly: OwinStartup("Startup", typeof(ApiStartup))]

namespace EdFi.Ods.WebApi.Startup
{
    public class ApiStartup : Api.Startup.Startup
    {
        protected override void EnsureAssembliesLoaded()
        {
            AssemblyLoader.EnsureLoaded<Marker_EdFi_Ods_Composites_Enrollment>();
            AssemblyLoader.EnsureLoaded<Marker_EdFi_Ods_Api_BulkLoad>();
            AssemblyLoader.EnsureLoaded<Marker_EdFi_Ods_Extensions_TPDM>();
            AssemblyLoader.EnsureLoaded<Marker_EdFi_Ods_Extensions_Sample>();
        }
    }
}

Adding a Feature

Features are new components for the system. It is recommended that a feature be implemented in its own assembly and then referenced into the web project.

Step 1. Create a New Assembly for the Feature

Install the Castle.Windsor package and reference EdFi.Ods.Common project.

Step 2. Add a New Feature Class

Implement IFeature from EdFi.Ods.Common. Add the Windsor Installer for the feature.

using System.Collections.Generic;
using Castle.MicroKernel.Registration;
using EdFi.Ods.Common;

namespace EdFi.Ods.TestFeature
{
    public class TestFeature : IFeature
    {
        public IList<IWindsorInstaller> Installers() => new List<IWindsorInstaller>( { new TestFeatureInstaller() });

        public bool IsEnabled() => true;
    }
}

Note: To set up your feature to be enabled or disabled in the app settings, inherit from ConfigurationBasedFeature and set the feature name, which will be a key for the feature in the configuration file (e.g., <add key="testFeature:featureIsEnabled" value="true"/>). Add the Windsor Installer for the feature.

using System.Collections.Generic;
using Castle.MicroKernel.Registration;
using EdFi.Ods.Common;
using EdFi.Ods.Common.Configuration;

namespace EdFi.Ods.TestFeature
{
    public class TestFeature : ConfigurationBasedFeature
    {
        public TestFeature(IConfigValueProvider configValueProvider)
            : base(configValueProvider) { }

        protected override string FeatureName => "TestFeature";

        public override IList<IWindsorInstaller> Installers() => new List<IWindsorInstaller>( { new TestFeatureInstaller() });
    }
}

Step 3. Create the Windsor Installer for the Feature

using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

namespace EdFi.Ods.TestFeature
{
    public class TestFeatureInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            // TODO add components to register.
        }
    }
}

Step 4. Modify WindsorContainerBuilder 

Add the feature to the container builder. 

        private void InstallCoreFeatures(IWindsorContainer container)
        {
            // Install the feature provider into the container.
                container.Register(
                    Component.For<IFeature>().ImplementedBy<RequiredApiStartupFeature>(),
                    Component.For<IFeature>().ImplementedBy<ChangeQueriesFeature>(),
                    Component.For<IFeature>().ImplementedBy<CompositesFeature>(),
                    Component.For<IFeature>().ImplementedBy<OpenApiMetadataFeature>(),
                    Component.For<IFeature>().ImplementedBy<ProfilesFeature>(),
                    Component.For<IFeature>().ImplementedBy<ExtensionsFeature>(),
                    Component.For<IFeature>().ImplementedBy<IdentityFeature>(),
                    Component.For<IFeature>().ImplementedBy<BulkApiFeature>(),
                    Component.For<IFeature>().ImplementedBy<TestFeature.TestFeature>(),
                    Component.For<IFeatureProvider>().ImplementedBy<FeatureProvider>());
        }

Miscellaneous Notes

When building a feature that requires a controller, implement the following interfaces: IRouteConfiguration and IOpenApiMetadataRouteConfiguration for setting up the routes, plus IOpenApiContentProvider for defining OpenApiMetadata. These interfaces are specific to using the feature within the ODS / API and is necessary for the controller. These interfaces are then registered within the installer.