Как я могу получить атрибут и свойства при использовании контекстной привязки Ninject?

У меня есть конструктор

[ReadFromFile(@"C:\SampleData\login.json")]
public AccountController(IReadRepository<LoginMockDataModel> repository, string filePath) : base(repository)
{
}

Атрибут содержит свойство "FilePath".

public string FilePath {get;set;}

Я хотел бы получить значение "FilePath", которое будет "C:\SampleData\login.json" в приведенном выше случае.

Можно ли получить значение, используя IContext от Ninject?

Идея состоит в том, чтобы извлечь значение свойства и затем использовать его в привязке следующим образом:

// FileReadRepo contains a constructor with the argument "filePath"
// which will need a string passed to it which I am trying to retrieve
// from the Attribute above
Bind(typeof(IReadRepository<>)).To(typeof(FileReadRepo<>))
.WhenMemberHas<ReadFromFileAttribute>()
.WithConstructorArgument("filePath", CheckAttributePath);

где CheckAttributePath будет делегатом:

private object CheckAttributePath(IContext arg)
{
    throw new NotImplementedException();
}

Я не уверен, как получить значение атрибута.

1 ответ

Решение

Доступ к конструктору AccountController делается через IContext.Request.Target.Member, Так что это работает:

private static object CheckAttributePath(IContext context)
{
    var attributes = context.Request.Target.Member
        .GetCustomAttributes(typeof(ReadFromFileAttribute), false);
    return ((ReadFromFileAttribute)attributes[0]).Path;
}

Полный тестовый код (использует xunit и FluentAssertions):

using System;
using Ninject;
using Ninject.Activation;
using Xunit;
using FluentAssertions;

public interface IReadRepository<T>
{
    string FilePath { get; }
}

public class FileReadRepo<T> : IReadRepository<T>
{
    private readonly string filePath;

    public FileReadRepo(string filePath)
    {
        this.filePath = filePath;
    }

    public string FilePath { get { return this.filePath; } }
}

[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
public class ReadFromFileAttribute : Attribute
{
    public readonly string Path;

    public ReadFromFileAttribute(string path)
    {
        this.Path = path;
    }
}

public class AccountController
{
    public readonly IReadRepository<string> Repository;

    [ReadFromFile(IntegrationTest.SampleFilePath)]
    public AccountController(IReadRepository<string> repository)
    {
        this.Repository = repository;
    }
}

public class IntegrationTest
{
    public const string SampleFilePath = @"C:\SampleData\login.json";

    [Fact]
    public void Test()
    {
        var kernel = new StandardKernel();

        kernel.Bind(typeof(IReadRepository<>)).To(typeof(FileReadRepo<>))
            .WhenMemberHas<ReadFromFileAttribute>()
            .WithConstructorArgument("filePath", CheckAttributePath);

        kernel.Get<AccountController>().Repository.FilePath.Should().Be(SampleFilePath);
    }

    private static object CheckAttributePath(IContext context)
    {
        var attributes = context.Request.Target.Member.GetCustomAttributes(
            typeof(ReadFromFileAttribute), false);
        return ((ReadFromFileAttribute)attributes[0]).Path;
    }
}
Другие вопросы по тегам