Как удалить повторяющиеся привязки Ninject? - PullRequest
1 голос
/ 04 февраля 2020

Мои текущие общие привязки: модуль Ninject

public class GeneralBindings : NinjectModule
    {
        public override void Load()
        {
            // Requires Ninject.Extensions.Conventions
            // This binds all interfaces to concretes of the same name eg IClass -> Class.
            Kernel.Bind(x => x.FromAssembliesMatching("Company.Project.Scm*")
                .SelectAllClasses()
                .Excluding(typeof(AffectedCables),
                    typeof(ApplicationConfigurations),
                    typeof(ApplicationErrors),
                    typeof(ApplicationLogEvents),
                    typeof(AppUsers),
                    typeof(AppUsersContract),
                    typeof(Areas)

                    // etc..

                )
                .BindAllInterfaces());

затем

            Bind<IAffectedCables>().To<AffectedCables>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AffectedCables");

            Bind<IApplicationErrors>().To<ApplicationErrors>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppErrors");

            Bind<IApplicationConfigurations>().To<ApplicationConfigurations>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppConfigurations");

            Bind<IApplicationLogEvents>().To<ApplicationLogEvents>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppEventLogs");

            Bind<IAppUsers>().To<AppUsers>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppUsers");

            Bind<IAppUsersContract>().To<AppUsersContract>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppUserContract");

            Bind<IAreas>().To<Areas>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/Areas");

            // Etc...
...

Кто-нибудь может подсказать, как сделать это лучше? Я уверен, что кто-то может создать одну строку кода, которая сохранит копию и вставку, которые я должен выполнить в данный момент.

Ответы [ 2 ]

1 голос
/ 04 февраля 2020

Слепой выстрел, не проверено, но я бы попробовал с атрибутом

public class AutoBindWithRouteAttribute : Attribute
{
    public string Route { get; }

    public AutoBindWithRouteAttribute(string route = null)
    {
        Route = route;
    }
}

, затем

    // to bind your first block of code for classes not featuring the attribute
    kernel.Bind(
        x => x.FromAssembliesMatching("").SelectAllClasses()
            .Where(t => !t.GetCustomAttributes(typeof(AutoBindWithRouteAttribute), false).Any())
           .BindAllInterfaces());

    // to bind your second block of code for classes featuring the attribute
    kernel.Bind(
        x => x.FromAssembliesMatching("").SelectAllClasses()
            .Where(t => t.GetCustomAttributes(typeof(AutoBindWithRouteAttribute), false).Any())
            .BindWith(new BindingGenerator()));

, где BindingGenerator:

public class BindingGenerator : IBindingGenerator
{
    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
    {
        var att =
            type.GetCustomAttributes(typeof(AutoBindWithRouteAttribute), false).FirstOrDefault() as
                AutoBindWithRouteAttribute;
        if (att == null) yield break;

        yield return (IBindingWhenInNamedWithOrOnSyntax<object>)bindingRoot
            .Bind(type.GetInterfaces().First())
            .To(type)
            .InSingletonScope()
            .WithConstructorArgument("url", att.Route ?? $"api/{type.Name}");
    }
}

использование будет тогда:

[AutoBindWithRoute()]
public class AffectedCables : IAffectedCables

[AutoBindWithRoute(@"api/AppErrors")]
public class ApplicationErrors : IApplicationErrors
0 голосов
/ 06 февраля 2020

Исходя из превосходного предложенного решения jbl, потому что у меня было

 public class AffectedCables : DataAccessBase<AffectedCableEntity>, IAffectedCables
    {
...
    }

BindingGenerator было обязательным DataAccessBase, поэтому я сделал небольшое изменение, чтобы вместо этого использовать связанный интерфейс:

public class BindingGenerator : IBindingGenerator
        {
            public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type,IBindingRoot bindingRoot)
            {
                var att =
                    type.GetCustomAttributes(typeof(AutoBindWithRouteAttribute), false).FirstOrDefault() as
                        AutoBindWithRouteAttribute;
                if (att == null) yield break;

                yield return (IBindingWhenInNamedWithOrOnSyntax<object>) bindingRoot
                    .Bind(type.GetInterfaces().First(x => x.Name == $"I{type.Name}"))
                    .To(type)
                    .InSingletonScope()
                    .WithConstructorArgument("url", att.Route ?? $@"api/{type.Name}");
            }
        }
...